Kbd
키보드 키 한 개 또는 키 조합을 키캡으로 보여 주는 컴포넌트
목차
키보드 키 하나 또는 키 조합을 키캡으로 보여 주는 컴포넌트입니다. 단축키 안내, 도움말 페이지, 커맨드 팔레트 등에서 활용합니다. 키 한 개는 키캡 하나이고, Kbd
하나는 조합 하나입니다. 키가 여러 개면 키캡을 받은 순서대로 나란히 놓으며, 키 사이에 + 같은 글자는 그리지 않습니다. 양쪽 플랫폼이 동일한 토큰 (labelXs
역할 · 본문 서체, surface 배경, outlineSubtle 0.5 테두리, CoreRadius.radius4) 으로 렌더됩니다. 키캡은 페이지와 같은 면에 가는 테두리로 구분됩니다 — 그림자는 기본값이 없어
keyShadow 에 적은 스택만 키마다 붙습니다.
기본 사용법 (Basic Usage)#
// 키 하나
const Kbd(keys: ['Esc'])
// 키 조합 (2개)
const Kbd(keys: ['Ctrl', 'C'])
// 키 3개
const Kbd(keys: ['Ctrl', 'Shift', 'P'])
// 키 4개 — OS 가 정한 단축키를 보여 줄 때만 (macOS: 화면 일부를 클립보드로)
const Kbd(keys: ['⌃', '⇧', '⌘', '4'])
// 맥 스타일
const Kbd(keys: ['⌘', 'K'])
// 방향키
const Kbd(keys: ['↑'])
// 단일 키 named ctor
Kbd.single(keyText: '⌘')
// 아이콘 글리프 키 named ctor — label 이 이 키의 접근 가능한 이름
const Kbd.icon(
keyContent: Icon(LucideIcons.cornerDownLeft),
label: '확인',
)
// 키캡 사이 간격 override
const Kbd(
keys: ['Ctrl', 'C'],
kbdStyle: CoreKbdStyle(keySeparatorSpacing: CoreSpace.space8),
)
// Flutter ShortcutActivator 에서 키 목록 추출 (Flutter 전용)
Kbd(
keys: kbdKeysFromActivator(
const SingleActivator(LogicalKeyboardKey.keyS, control: true),
),
)
// 키 하나
const Kbd(keys: ['Esc'])
// 키 조합 (2개)
const Kbd(keys: ['Ctrl', 'C'])
// 키 3개
const Kbd(keys: ['Ctrl', 'Shift', 'P'])
// 키 4개 — OS 가 정한 단축키를 보여 줄 때만 (macOS: 화면 일부를 클립보드로)
const Kbd(keys: ['⌃', '⇧', '⌘', '4'])
// 맥 스타일
const Kbd(keys: ['⌘', 'K'])
// 단일 키 named ctor
Kbd.single(keyText: '⌘')
// 아이콘 글리프 키 named ctor — label 이 이 키의 접근 가능한 이름
const Kbd.icon(
keyContent: Icon(LucideIcons.cornerDownLeft),
label: '확인',
)
// 키캡 사이 간격 override
const Kbd(
keys: ['Ctrl', 'C'],
kbdStyle: CoreKbdStyle(keySeparatorSpacing: CoreSpace.space8),
)
빠른 오버라이드 (Chain)#
이미 만든 Kbd 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 style 슬롯 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.
class KbdChainExample extends StatelessWidget {
const KbdChainExample({super.key});
@override
Widget build(BuildContext context) {
return const Kbd(keys: ['Ctrl', 'C']).withStyle(
const CoreKbdStyle(
keyRadius: CoreBorderRadius.all(CoreRadius.radius9999),
keyBackgroundColor: CoreColor.token(CoreColors.primaryContainer),
keyBorderColor: CoreColor.token(CoreColors.primary),
keyBorderWidth: CoreStrokeWidth.stroke2,
keyPadding: CoreEdgeInsets.symmetric(
horizontal: CoreSpace.space12,
vertical: CoreSpace.space6,
),
keyTextStyle: CoreTextStyle.token(
CoreTextStyles.labelMedium,
color: CoreColor.token(CoreColors.onPrimaryContainer),
),
),
);
}
}
class KbdChainExample extends StatelessComponent {
const KbdChainExample({super.key});
@override
Component build(BuildContext context) {
return const Kbd(keys: ['Ctrl', 'C']).withStyle(
const CoreKbdStyle(
keyRadius: CoreBorderRadius.all(CoreRadius.radius9999),
keyBackgroundColor: CoreColor.token(CoreColors.primaryContainer),
keyBorderColor: CoreColor.token(CoreColors.primary),
keyBorderWidth: CoreStrokeWidth.stroke2,
keyPadding: CoreEdgeInsets.symmetric(
horizontal: CoreSpace.space12,
vertical: CoreSpace.space6,
),
keyTextStyle: CoreTextStyle.token(
CoreTextStyles.labelMedium,
color: CoreColor.token(CoreColors.onPrimaryContainer),
),
),
);
}
}
Live Preview#
코드 보기
class KbdSingleExample extends StatelessComponent {
const KbdSingleExample({super.key});
@override
Component build(BuildContext context) {
return const Kbd(keys: ['Esc']);
}
}
class KbdSingleExample extends StatelessWidget {
const KbdSingleExample({super.key});
@override
Widget build(BuildContext context) {
return const Kbd(keys: ['Esc']);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 단축키나 키보드 조합을 사용자에게 시각적으로 안내할 때
- 도움말 페이지나 온보딩에서 키보드 인터랙션을 설명할 때
- 커맨드 팔레트의 항목 옆에 단축키를 표시할 때
- 접근성 안내 문서에서 키보드 탐색 방법을 설명할 때
-
Flutter
ShortcutActivator에 등록한 단축키를 그대로 보여 줄 때 (kbdKeysFromActivator, Flutter 전용)
대신 다른 컴포넌트를 사용하세요:
- CodeSnippet: 키 조합 대신 여러 줄 코드·복사 기능이 필요할 때
-
Text: 키 박스 없이 문자열만 표시할 때. 문장 안에서 단축키를 적을 때도
Ctrl+S처럼 글자로 씁니다 —Kbd는 문장 밖에서 키캡으로 보여 줄 때만 씁니다
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
keys |
List<String> |
필수 | 표시할 키 목록. 받은 순서대로 키캡을 나란히 놓습니다. 키 사이에 글자를 그리지 않습니다 |
kbdStyle |
CoreKbdStyle? |
null |
padding / spacing / radius / 색 / 텍스트 chrome override |
label |
String? |
null |
Kbd.icon
키의 접근 가능한 이름.
Kbd.icon
전용이며, 텍스트 키의 이름은
keys
에서 만들어집니다
|
keyContent (Widget? / Component?) 와 label 은 기본 생성자에는 없고
Kbd.icon(keyContent: …, label: …) 전용입니다 — 단일 칩에 아이콘 글리프를 넣어 심볼 텍스트 글리프의 플랫폼별 폰트 fallback 을 피할 때 씁니다.
keyContent 는 keys 와 상호배타이며 (Kbd.icon 은 keys 가 빈 목록),
copyWith 로도 교체되지 않습니다. 아이콘 글리프는 스크린 리더에 아무것도 말하지 않으므로 label 을 주지 않으면 그 키는 침묵합니다 — 이웃 텍스트가 이미 동작을 말하는 자리(푸터의 "이동" 옆 화살표 키)에서는 일부러 비워 둡니다.
kbdKeysFromActivator(ShortcutActivator) 는 Flutter 전용 최상위 함수이며 List<String>
을 돌려줍니다. 수정키는 Apple HIG 순서(Ctrl → Alt → Shift → ⌘)로 먼저 오고 마지막에 트리거 키가 옵니다. Web 에는 ShortcutActivator
가 없으므로 키 목록을 직접 넘깁니다.
스타일 시스템 (Style System)#
모든 chrome / dimensional / 텍스트 override 는 kbdStyle 슬롯 하나로 흐릅니다. 키캡 사이 간격은 keySeparatorSpacing
하나이고 기본값은 CoreSpace.space4 (4px) 입니다. 구분자 글자가 없으므로 이 간격만이 이웃 키캡(과 키캡에 적은 그림자)이 맞닿지 않게 합니다.
CoreKbdStyle 필드#
| 필드 | 타입 | 설명 |
|---|---|---|
keyPadding |
CoreEdgeInsets? |
Padding inside each key box. |
keySeparatorSpacing |
double? |
Spacing (logical px) between adjacent key boxes — rendered as
Row.spacing
(Flutter) / flex container
gap
(Web). N-sibling 균등 분포 (Key, Key, Key) 패턴. See [defaultKeySeparatorSpacing].
|
keyMinSize |
double? |
Minimum key-box square extent — see [defaultKeyMinSize]. |
keyRadius |
CoreBorderRadius? |
Border radius of key boxes. |
keyBackgroundColor |
CoreColor? |
Background colour of each key box. |
keyBorderColor |
CoreColor? |
Border colour of each key box. |
keyBorderWidth |
double? |
Border stroke width of each key box — see [defaultKeyBorderWidth]. Drawn only while [keyBorderColor] is visible. |
keyShadow |
List<CoreShadowLayer>? |
Shadow of each key box — see [defaultKeyShadow]. An empty list draws no shadow. |
keyTextStyle |
CoreTextStyle? |
Text style applied to the key label characters. |
Resolve chain#
design system default (CoreKbdStyle.defaultX static const)
→ CoreKbdTheme.style // 프로젝트 공통
→ parent component slot override
→ widget.kbdStyle // 인스턴스별
동작 스펙 (Behavior)#
인터랙션#
- 표시 전용 컴포넌트 — 클릭/호버 인터랙션 없음.
- keys를 전달한 순서로 표시하며 빈 목록은 키 박스를 그리지 않습니다. 실제 단축키 바인딩·키 이벤트·비활성 상태는 없습니다. Kbd.icon은 keyContent 하나를 키 박스 안에 표시합니다.
레이아웃#
-
루트는
inline-flexrow — 키 박스를 받은 순서대로 나열하고, 키 박스 사이는keySeparatorSpacing(기본CoreSpace.space4) 만 띄웁니다. 키 사이에 그리는 글자는 없습니다. -
각 키 박스: 최소 정사각
CoreSize.size18(keyMinSize) + paddingCoreSpace.space2(수직) /CoreSpace.space6(수평). 높이는 라벨 줄(11 × 1.4 = 15.4) + 위아래 2 = 19.4 에 기본 테두리 0.5 가 양쪽에 더해져 20.4 입니다. 테두리 색이 투명이면 폭을 0 으로 접어 레이아웃을 먹지 않습니다(양 플랫폼 동일). 하한(18)은 폭이 좁은 글자와 아이콘 키에서만 걸립니다. -
테두리 색
outlineSubtle· 폭CoreStrokeWidth.stroke0_5(헤어라인), 배경surface, 라운드CoreRadius.radius4, 그림자 없음 (CoreShadow.none—keyShadow에 스택을 적으면 그 스택). - 적은 그림자는 키 박스마다 붙습니다 — 키를 늘어놓은 줄(row)에는 붙지 않습니다. 표면 스타일은 적은 스택을 굽힐 뿐 키에 자기 캐스트나 림을 더하지 않습니다.
-
한 줄을 유지하고 줄어들지 않습니다. Web 키 박스는
flex-shrink: 0이고 Flutter 키 박스도 줄어들지 않습니다. 칸이 모자라면 글자가 잘리는 대신 조합이 칸 밖으로 넘칩니다 (Web 은 밖으로 삐져나오고, Flutter 는 개발 모드에서 Row 오버플로 오류로 보고됩니다).
키 수와 너비#
코드에는 키 수 상한이 없어 4개도 그대로 그려집니다. 너비는 구분자가 없는 상태(간격 4)에서의 실측입니다.
다시 재야 하는 값입니다. 아래 너비와 이 페이지가 인용하는 키 조합 폭(92 · 96 · 147px)은 키 글자가 고정폭 서체의
labelSmall(10px)이던 때 잰 것입니다. 지금 키 글자는 본문 서체의labelXs(11px)라 글자 폭이 달라졌고, 아직 다시 재지 않았습니다. 글자 하나짜리 키는 최소 정사각(keyMinSize18)이 너비를 정하는 경우가 많아 차이가 작고, 글자가 많은 키(Shift·Ctrl)일수록 차이가 큽니다.
| 조합 | Flutter | Web |
|---|---|---|
⌃ ⇧ ⌘ 4 (4개) | 약 96px | 약 92px |
Ctrl Alt Shift F5 (4개) | 약 147px | 약 147px |
기본 메뉴 패널(240 ~ 280px) 안에서는 둘 다 넘치지 않으며, 같은 행의 라벨이 줄바꿈하며 자리를 양보합니다. 80 ~ 120px 로 고정한 칸에서는 넘칩니다 — 4개 키를 그런 칸에 넣지 마세요.
토큰#
| 항목 | Flutter | Web |
|---|---|---|
| 키 폰트 | labelXs 역할 (11px · 본문 서체) |
labelXs 역할 (11px · 본문 서체) |
| 키 폰트 굵기 | 역할의 500 | 역할의 500 |
| 키 색 | colorScheme.onSurfaceVariant |
text-${cs.onSurfaceVariant} |
| 키 배경 | colorScheme.surface | bg-${cs.surface} |
| 키 보더 | outlineSubtle + 폭 0.5 |
border border-outline-subtle
+
var(--coui-stroke-width-0_5)
— 색을 투명으로 적으면 폭 0 ·
border
클래스 없음
|
| 키 그림자 (적었을 때) | InjectedCast (박스 바깥에만 칠함) |
inline box-shadow (예: var(--shadow-xs)) |
| 키 radius | BorderRadius.circular(CoreRadius.radius4) |
inline border-radius |
| 키 사이 간격 | Row.spacing = keySeparatorSpacing |
flex gap = keySeparatorSpacing |
예시 단축키#
// 복사
const Kbd(keys: ['Ctrl', 'C'])
// 붙여넣기
const Kbd(keys: ['Ctrl', 'V'])
// 전체 선택
const Kbd(keys: ['Ctrl', 'A'])
// 커맨드 팔레트 (macOS)
const Kbd(keys: ['⌘', 'K'])
// 저장
const Kbd(keys: ['Ctrl', 'S'])
// 실행 취소
const Kbd(keys: ['Ctrl', 'Z'])
// 화면 일부를 클립보드로 (macOS, OS 가 정한 단축키 — 4개 키)
const Kbd(keys: ['⌃', '⇧', '⌘', '4'])
사용 가이드라인 (Usage Guidelines)#
키는 몇 개까지 (Key Count)#
앱이 정하는 단축키는 3개까지. 4개는 OS가 정한 단축키(⌃⇧⌘4 등)를 보여 줄 때만.
| 키 수 | 쓰는 곳 |
|---|---|
| 1 ~ 3 | 앱이 정하는 단축키 |
| 4 | OS 가 정한 단축키를 보여 줄 때만 |
4개 키의 폭은 ⌃ ⇧ ⌘ 4 가 약 92 ~ 96px (Web 92 · Flutter 96), Ctrl Alt Shift F5 가 약 147px 입니다 — 기본 메뉴 패널(240 ~ 280px)에는 들어가지만 80 ~ 120px 로 고정한 칸에는 넘칩니다. 앱이 직접 정하는 단축키는 3개 안에서 해결하세요.
✅ Do#
플랫폼에 따라 다른 키 표기를 사용하세요. Kbd 는 받은 글자를 그대로 보여 줄 뿐 OS 를 보고 표기를 바꾸지 않으므로, 어느 표기를 쓸지는 호출하는 쪽이 정합니다:
const Kbd(keys: ['⌘', 'K']) // macOS
const Kbd(keys: ['Ctrl', 'K']) // Windows / Linux
문장 안에서 단축키를 적을 때는 Kbd 가 아니라 글자로 쓰세요 (예: "저장은 Ctrl+S 입니다"). Kbd 는 문장 밖에서 키를 키캡으로 보여 줄 때의 컴포넌트입니다.
❌ Don't#
앱이 정하는 단축키에 4개 키를 쓰지 마세요. 가독성이 급격히 저하되고 폭이 147px 까지 늘어납니다 (앱 단축키는 3개까지).
// ❌
const Kbd(keys: ['Ctrl', 'Alt', 'Shift', 'F5'])
4개 키를 80 ~ 120px 로 고정한 칸에 넣지 마세요. 키 박스가 줄어들지 않으므로 조합이 칸 밖으로 넘칩니다.
키 사이에 + 를 직접 끼워 넣지 마세요. 키캡이 이미 키를 나누고 있고, 간격은 keySeparatorSpacing 이 정합니다.
Kbd 를 클릭 가능한 버튼처럼 사용하지 마세요. 표시 전용입니다 — 클릭이 필요하면 Button 을 쓰세요.
접근성 (Accessibility)#
역할#
Kbd 하나는 조합 하나이며 접근 이름도 하나입니다. 키캡 하나하나가 따로 읽히지 않습니다.
-
Web: 루트
<span>이role="img"와aria-label을 가지며, 안의 키캡은 장식(presentational)입니다. 네이티브<kbd>요소를 쓰지 않습니다. - Flutter: 루트가 하나의 병합된 의미 노드이며, 안쪽 키캡 텍스트는 의미 트리에서 빠집니다.
키보드#
처리하는 키가 없고, 붙일 수도 없습니다. Web Kbd 의 세 생성자는 keys / keyContent
/ label / kbdStyle 과 attributes / classes / css
/ id 만 받고 eventHandlers · onKeyDown · onClick 을 노출하지 않아 루트에 실리는
events 맵이 항상 비어 있습니다. Flutter 쪽도 생성자에 콜백 파라미터가 없습니다.
이 컴포넌트는 단축키를 표시할 뿐 실행하지 않습니다 — 실제 키 바인딩은 그 단축키를 소유한 컴포넌트 쪽에 있습니다.
스크린 리더#
접근 가능한 이름의 출처는 keys 에 넣은 문자열입니다. 텍스트 키는 키 글자를 공백으로 이은 하나의 이름으로 읽힙니다 — Kbd(keys: ['Ctrl', 'S'])
는 "Ctrl S" 입니다. 키 사이에 글자를 그리지 않으므로 "+" 도 읽히지 않습니다. ⌘ 같은 기호 키는 글자 그대로 이름에 들어가며, 어떻게 발음되는지는 스크린 리더에 달려 있습니다.
Kbd.icon 은 label 이 그 키의 이름입니다 — Kbd.icon(keyContent: …, label: '위로')
는 "위로" 로 읽힙니다. label 을 주지 않은 Kbd.icon 은 아무것도 읽지 않습니다. 이웃 텍스트가 이미 동작을 말하는 자리(커맨드 푸터의 "이동" 옆 화살표 키)에서는 침묵이 맞고, 키가 혼자 서 있는 자리에서는
label 을 주세요.
상태 통보는 없습니다 — live region 배선이 어느 쪽에도 없습니다.
포커스 관리#
포커스 대상이 아닙니다. Flutter 에 FocusNode / Focus 가 없고 Web 에 tabindex 가 없어 어느 플랫폼에서도 traversal 정지점이 되지 않습니다. 오버레이가 아니므로 진입·이탈·트랩 모두 해당 없습니다.
알려진 제약#
-
aria-keyshortcuts를 내보내지 않습니다.Kbd는 단축키를 표시만 합니다. 단축키를 가진 컨트롤이 스크린 리더에 단축키를 알리게 하려면 그 컨트롤 쪽에aria-keyshortcuts를 직접 넣어야 합니다. -
Web 루트 태그를
<kbd>로 바꿀 수 없습니다. 세 생성자가 모두 루트를<span>으로 고정하므로 호출자가 네이티브 키보드-입력 시맨틱을 얻을 방법이 없습니다. 접근 이름은role="img"+aria-label이 대신합니다. -
색 강제 모드에서 키캡 자체의 경계는 없습니다. 키캡은 선도 그림자도 그리지 않는 평평한 표면이고(경계 없음이 디자인), 구분은 면의 톤 대비가 맡습니다. 색을 시스템 색으로 강제하는 모드에서는 그 톤 대비가 사라지므로 키캡을 구분하는 것은 강제되는 글자 색입니다. 강제색 경계를 진술하는 표면 스타일 아래에서만 Web 이 표시된 표면(키캡 포함)에 경계를 붙입니다 — Flutter 에는 대응하는 경로가 없습니다. 키캡을 항상 상자로 읽게 해야 하는 앱은
kbdStyle에 보이는keyBorderColor를 적습니다. -
최소 크기 축은 대상이 아닙니다. 키 캡의 최소 정사각은
CoreSize.size18(18px) 로 24px 미만이지만, 어느 플랫폼에도 포인터 핸들러가 없어 (위 "키보드" 절) 최소 터치 타깃 규정이 적용되지 않습니다.
모션 감소 · 고대비 · 최소 터치 타깃처럼 모든 컴포넌트에 공통으로 적용되는 축은 전역 접근성 축 에 정리되어 있습니다.
크로스 플랫폼 차이점 (Platform Differences)#
| 항목 | Flutter | Web |
|---|---|---|
| 키 나열 | Row.spacing과 키 박스 | span 래퍼 안의 키 span 들을 flex gap 으로 나열 |
| 키 사이 글자 | 없음 | 없음 |
| 좁은 칸 | 키 박스가 줄어들지 않고 Row 오버플로로 보고 | flex-shrink: 0 으로 줄어들지 않고 칸 밖으로 넘침 |
| 접근 이름 | 병합된 의미 노드 하나 (키캡 텍스트는 의미 트리에서 제외) | 루트 <span role="img" aria-label>, 키캡은 장식 |
| 텍스트 | 해석된 TextStyle | 역할 클래스 text-label-xs |
| 키보드 의미 | 표시 텍스트만 | native kbd가 아닌 span 텍스트 |
| 아이콘 키 | Widget keyContent + label | Component keyContent + label |
ShortcutActivator 변환 |
kbdKeysFromActivator (수정키 Ctrl → Alt → Shift → ⌘, 그다음 키) |
없음 — 키 목록을 직접 넘김 |
| 헤어라인 보더 (색을 적었을 때) | 0.5 그대로 | 1배 화면 1px, 2배 이상 0.5px (--coui-stroke-width-0_5) |
| 투명한 테두리 | 폭 0 (Border.all 이 박스를 키우지 않게) |
폭 0 + border 클래스 없음 |
| 키 그림자 (적었을 때) | 박스를 파낸 채로 바깥에만 (InjectedCast) |
CSS box-shadow (원래 바깥에만) |
| 표면 프리셋 | 프리셋이 키가 적은 스택을 굽힌다 (스택이 없으면 아무것도 더하지 않는다) | 프리셋이 --shadow-* 를 다시 가리켜 적은 스택을 굽힌다 |
KeyboardShortcut 에서 옮겨 오기#
KeyboardShortcut 컴포넌트는 없습니다. 같은 일을 Kbd 가 합니다.
| 이전 | 이후 |
|---|---|
KeyboardShortcut(keys: k) | Kbd(keys: k) |
KeyboardShortcut(keys: k, spacing: s) |
Kbd(keys: k, kbdStyle: CoreKbdStyle(keySeparatorSpacing: s)) |
KeyboardShortcut.fromActivator(activator: a) (Flutter) |
Kbd(keys: kbdKeysFromActivator(a)) |
그대로 치환하면 모양이 달라집니다.
-
키 사이의
+글자가 없고, 키캡 간격 기본값은space2가 아니라space4입니다. 문장 안에서 단축키를 적을 때의+는Ctrl+S처럼 글자로 씁니다. -
fromActivator가 내던 수정키 순서 Ctrl → Alt → ⌘ → Shift 는 Apple HIG 의 Ctrl → Alt → Shift → ⌘ 가 됩니다. -
CoreKeyboardShortcutStyle·CoreKeyboardShortcutTheme·CoreComponentTheme.keyboardShortcut이 없으므로 간격은CoreKbdStyle.keySeparatorSpacing으로 줍니다.CoreKbdStyle.separatorTextStyle도 없습니다 — 그릴 구분자가 없습니다. -
Flutter 의
KeyboardShortcutDisplayMapper·KeyboardShortcutDisplayHandle·KeyboardShortcutDisplayBuilder도 함께 없어졌습니다.
관련 컴포넌트 (Related Components)#
- CodeSnippet: 여러 줄 코드나 명령어 블록 표시
-
Command: 푸터에 키 하나짜리
Kbd힌트를 놓는 커맨드 팔레트 - Tooltip: 아이콘 버튼의 단축키 안내에 함께 사용