개발/Visual Studio Code

커맨드 팔레트 46부: VS Code Task 종료 단축키의 매칭 로그로 충돌 진단하기

반응형
VS CODE 초보자 시리즈 · 커맨드 팔레트 46부

커맨드 팔레트 46부: VS Code Task 종료 단축키의 매칭 로그로 충돌 진단하기

종료 단축키가 다른 명령을 실행하는 원인을 실제 로그로 좁히고, 충돌한 User 규칙의 when 하나만 수정해 연습 Target만 종료합니다.

같은 chord의 수정 전·후 원문 로그를 보존하고, matched 명령이 sidebar 토글에서 tasks.terminate로 바뀐 것과 Target 종료·Guard 지속 실행을 독립적으로 확인한 뒤 실습 변경을 되돌립니다.

같은 키의 아래쪽 User 규칙이 종료 명령 대신 선택되는 원인을 로그로 확인합니다.

1. 시작하기 전에

예상 시간은 20~30분입니다. 앞선 45부의 선택·Find 잠금 조건을 그대로 사용하지만, 이번 목표는 규칙의 실제 선택 과정을 읽는 것입니다. JSON은 이름과 값을 짝지어 저장하는 형식이며, 여기서는 기존 배열에 객체 두 개를 추가하고 한 문자열만 수정합니다.

적용 환경: Windows 11, VS Code Stable 1.137.0, Windows PowerShell 5.1(powershell.exe). 2026-09-14 조사에서 Microsoft Stable API와 로컬 CLI가 같은 commit 645f29cc3176500b4b5762ba887cf2a7f0ffdf2c를 반환했습니다. PowerShell 7을 기본 Terminal로 사용해도 예제 Task는 powershell.exe를 직접 실행합니다. 영어 명령 이름을 기준으로 안내하며 번역 UI의 문구는 다를 수 있습니다.

준비할 것:

  • VS Code 설치 확인: 별도의 PowerShell에서 code --version을 실행합니다. CLI를 찾지 못하면 Help > About에서 버전을 확인합니다. 이 글은 설치·업데이트를 요구하지 않습니다.
  • PowerShell 확인: Windows PowerShell 창에서 $PSVersionTable.PSVersion을 읽습니다. 이 글의 Task는 Windows PowerShell 5.1을 전제로 합니다.
  • 자기 연습 폴더만 열고 자신이 만든 tasks.json을 검토합니다. Restricted Mode이면 Tasks 실행을 진행하지 않습니다. 낯선 저장소를 신뢰해 실습을 강행하지 않습니다.
  • User keybindings.json을 열고 기존 내용을 복사·저장할 수 있어야 합니다. 동기화 중이면 기존 선택에 따라 이 변경도 다른 기기로 반영될 수 있으므로 보호할 계정·기기를 먼저 확인합니다.

안전하게 시작하기: 종료 시험은 최대 300초 동안 문자열만 출력하는 연습 Task에 한정합니다. 실무 빌드·서버·배포 Task는 모두 별도 창에서 보호합니다. User 단축키는 다른 폴더에서도 적용되므로 첫 쓰기 전에 전체 백업을 확보합니다. Human Gate는 독자가 연습 폴더·Task label·백업을 직접 확인하는 시점입니다. 백업 실패, 기존 파일 존재, 예상 밖 명령 호출, label 불일치, 다른 Task 종료가 보이면 중단하고 원문과 현재 상태를 보존합니다. 실습 규칙 두 개 제거와 연습 Task 종료가 기본 Rollback이며, 다른 변경이 없을 때만 전체 백업 복원을 사용합니다.

기준 버전 근거: S1 S2

2. 알아둘 핵심 개념

FACT — 입력 수신, 매칭, 호출, 결과는 각각 다릅니다

Received는 VS Code가 키 이벤트를 받은 기록, Converted는 내부 키 표현으로 바꾼 기록입니다. Resolving은 누른 키와 현재 chord를 후보 규칙에 대조합니다. matched는 선택된 명령·조건·출처, Invoking command는 명령 호출입니다. 마지막 줄이 있어도 Task 종료 완료는 별도 검증해야 합니다.

근거: S8 S9 S10

FACT — chord와 조건

ctrl+k ctrl+alt+t는 Ctrl+K를 누르고 모두 놓은 뒤 Ctrl+Alt+T를 누르는 두 조합입니다. 첫 조합의 awaiting 1 more chord(s)는 다음 입력을 기다리는 정상 상태입니다. when은 String으로 작성한 Boolean 조건식이며 입력 위치의 Context에 따라 평가됩니다. &&는 모두 참, !는 부정입니다. 새 조건을 추가하지 않고 45부 조건을 그대로 유지합니다.

근거: S4 S10

FACT — 같은 키의 규칙 순서

User keybindings.json의 규칙은 기본 규칙 뒤에 붙고, 후보는 아래에서 위로 평가됩니다. key와 when이 함께 맞는 첫 규칙이 선택됩니다. 조건이 길거나 좁다고 자동 우선하지 않습니다. source: user는 User 규칙, built-in은 기본 규칙, extension 표시는 확장 출처입니다. 후보가 2개라는 숫자는 명령 2개가 실행됐다는 뜻이 아닙니다.

근거: S9

EXAMPLE — 두 Task와 하나의 충돌

Target은 종료 대상, Guard는 계속 살아 있어야 하는 비교 대상입니다. 아래의 sidebar 토글 규칙은 데이터 변경 없이 충돌을 재현하는 자체 예제입니다. key·command·args·when은 모두 String이며 두 규칙은 User 범위입니다. tasks.json은 열린 연습 폴더의 Workspace Folder 범위입니다. args는 종료할 label을 지정합니다. 로그는 args를 표시하지 않으므로 JSON과 대조해야 합니다.

근거: S5 S11

RECOMMENDATION — 원문과 해석을 분리하세요

원문 로그 파일에는 시간·철자·후보 수를 그대로 둡니다. 원인 설명은 별도 메모에 적고 확인되지 않으면 UNKNOWN이라고 기록합니다. 수정 후에도 동일한 입력 위치에서 다시 검사하세요. source와 when의 글자 순서는 출력 정규화로 달라질 수 있으므로 논리적 의미를 비교합니다.

근거: S9

3. 순서대로 진행하기

S01. 새 연습 폴더를 만듭니다

PROCEDURE · 목적 기존 프로젝트 파일을 보호합니다.

주의·되돌리기 기존 경로에 덮어쓰지 않습니다. 연습 폴더는 자동 삭제하지 않고 종료 후 보관해도 됩니다.
  1. 아래 명령으로 새 연습 폴더와 .vscode 하위 폴더를 만듭니다.

입력 위치 Shell: 별도의 Windows PowerShell. 실행 위치: 어느 폴더든 가능; 경로는 현재 사용자 홈에서 계산합니다.

$labDir = Join-Path $env:USERPROFILE 'JCOS-VSC46-Log-Lab'
if (Test-Path -LiteralPath $labDir) { throw '연습 폴더가 이미 있습니다. 중단하세요.' }
New-Item -ItemType Directory -Path (Join-Path $labDir '.vscode')
정상 결과 현재 사용자 홈에 JCOS-VSC46-Log-Lab/.vscode가 생성됩니다.

확인 PowerShell의 생성 결과 경로를 확인합니다. 명령에는 치환할 Placeholder가 없습니다.

실패 신호 폴더가 이미 있다는 오류 또는 다른 프로젝트가 열려 있습니다.

복구와 재합류 기존 폴더는 보존하고 다른 미사용 이름을 직접 정합니다. 이후 모든 파일은 실제로 열린 새 폴더 기준입니다. 확인 후 S01에서 재합류합니다.

근거: S5

S02. 새 연습 폴더만 엽니다

PROCEDURE · 목적 설정 파일을 저장할 Workspace Folder를 확정합니다.

주의·되돌리기 Human Gate: 본인이 생성한 연습 내용인지 확인합니다. 낯선 저장소를 신뢰해서 Tasks를 강행하지 않습니다. 폴더를 닫으면 현재 창 선택을 되돌릴 수 있습니다.
  1. VS Code의 File > Open Folder에서 방금 만든 JCOS-VSC46-Log-Lab을 선택합니다.

입력 위치 VS Code Open Folder 대화상자; 실제 사용자 홈 아래의 연습 폴더.

Explorer 최상위 폴더: JCOS-VSC46-Log-Lab
하위 폴더: .vscode
정상 결과 Explorer에 연습 폴더와 .vscode가 보입니다.

확인 열린 최상위 이름과 경로를 생성한 폴더와 대조합니다. 자신이 만든 내용만 있는지 확인합니다.

실패 신호 다른 프로젝트가 열렸거나 Restricted Mode입니다.

복구와 재합류 다른 폴더에 쓰지 않고 새 연습 폴더를 다시 선택합니다. 자신이 만든 연습 내용임을 확인할 수 없으면 중단합니다. 올바른 폴더 확인 후 S03으로 이동합니다.

근거: S5

S03. 현재 User 단축키를 백업합니다

PROCEDURE · 목적 User 범위 변경을 되돌릴 기준을 확보합니다.

주의·되돌리기 Human Gate: 백업 일치와 동기화 영향 확인 전에는 규칙을 추가하지 않습니다. 원본을 Save As로 이동하거나 대체하지 않습니다.
  1. Command Palette에서 Preferences: Open Keyboard Shortcuts (JSON)을 실행하고 전체 내용을 연습 폴더의 keybindings-before.jsonc로 복사·저장합니다.

입력 위치 VS Code Command Palette; 이후 현재 Profile의 User keybindings.json. 백업은 연습 폴더의 별도 파일입니다.

백업 파일: keybindings-before.jsonc
기록: 원본 파일의 현재 Profile·경로·저장 시각
정상 결과 원본과 백업의 전체 내용이 같습니다.

확인 백업 파일을 다시 열어 첫 줄·마지막 줄·기존 객체 개수를 원본과 대조합니다.

실패 신호 백업이 비었거나 원본 저장 위치를 모르거나 내용이 다릅니다.

복구와 재합류 User 파일을 수정하지 않고 복사를 다시 합니다. 완전한 백업을 확인한 뒤 S04으로 이동합니다.

근거: S3

S04. 출력 전용 연습 Task를 저장합니다

EXAMPLE · 목적 종료 결과와 보호 대상을 눈으로 구별합니다.

주의·되돌리기 각 명령은 콘솔 출력과 대기만 합니다. 설치·삭제·외부 전송·자동 실행은 없습니다. RUN_ID의 실제 값은 매 실행 달라집니다. label를 바꾸면 S06의 args도 정확히 맞춰야 합니다.
  1. 새 폴더의 .vscode/tasks.json에 아래 전체 예제를 저장합니다.

입력 위치 VS Code 파일 편집기; Workspace Folder 범위 .vscode/tasks.json.

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "JCOS Log Lab Target",
      "type": "process",
      "command": "powershell.exe",
      "args": [
        "-NoProfile",
        "-Command",
        "$id=[guid]::NewGuid().ToString('N').Substring(0,8); Write-Output ('LOG_LAB_TARGET RUN_ID='+$id); for($i=0;$i -lt 300;$i++){ Write-Output ('LOG_LAB_TARGET HEARTBEAT='+$i); Start-Sleep -Seconds 1 }"
      ],
      "problemMatcher": [],
      "presentation": {
        "reveal": "always",
        "panel": "dedicated",
        "clear": true
      }
    },
    {
      "label": "JCOS Log Lab Guard",
      "type": "process",
      "command": "powershell.exe",
      "args": [
        "-NoProfile",
        "-Command",
        "$id=[guid]::NewGuid().ToString('N').Substring(0,8); Write-Output ('LOG_LAB_GUARD RUN_ID='+$id); for($i=0;$i -lt 300;$i++){ Write-Output ('LOG_LAB_GUARD HEARTBEAT='+$i); Start-Sleep -Seconds 1 }"
      ],
      "problemMatcher": [],
      "presentation": {
        "reveal": "always",
        "panel": "dedicated",
        "clear": true
      }
    }
  ]
}
정상 결과 JCOS Log Lab Target·Guard 두 Task 정의가 저장됩니다.

확인 JSON 오류 표시가 없고 두 label과 출력 marker가 각각 다릅니다. command는 String, args는 String 배열, problemMatcher는 빈 배열, clear는 Boolean입니다. presentation.reveal·panel은 String입니다.

실패 신호 JSON 오류, 다른 tasks.json 존재, powershell.exe를 찾지 못합니다.

복구와 재합류 실제 오류 원문을 보존합니다. 기존 파일이 있으면 덮어쓰지 말고 S01의 새 폴더를 다시 확인합니다. 쉼표·따옴표 수정 후 S04에서 재검사합니다.

근거: S5

S05. 시험할 chord의 기존 충돌을 확인합니다

PROCEDURE · 목적 예제 밖의 명령이 실행되지 않게 합니다.

주의·되돌리기 Human Gate: 기존 작업에 필요한 규칙을 삭제하지 않습니다. 백업 없이는 진행하지 않습니다.
  1. Preferences: Open Keyboard Shortcuts에서 ctrl+k ctrl+alt+t와 같은 전체 조합을 검색하고, 항목이 있으면 Show Same Keybindings로 모든 기존 규칙을 확인합니다.

입력 위치 Keyboard Shortcuts 편집기; Keybinding·When·Source 열.

시험할 chord: ctrl+k ctrl+alt+t
다른 전체 chord를 고르면 S06의 두 key를 동일하게 치환
정상 결과 예제에 쓸 전체 조합에 보호할 기존 규칙이 없습니다.

확인 Ctrl+K로 시작하는 다른 조합과 전체 chord가 같은 규칙을 구별합니다. 기본 접두 후보가 많이 보이는 것은 정상입니다.

실패 신호 기존 업무 규칙 또는 예상 밖 확장 규칙과 같은 전체 조합입니다.

복구와 재합류 기존 규칙은 유지하고 미사용 chord를 고릅니다. 두 예제 key를 함께 바꾸고 S05에서 다시 확인합니다.

근거: S3

S06. 의도적으로 충돌하는 User 규칙 두 개를 추가합니다

EXAMPLE · 목적 통제된 재현 조건을 만듭니다.

주의·되돌리기 변경 영향은 현재 User 단축키 전반입니다. sidebar 토글은 패널 표시만 바꾸지만 업무 중 다른 창에서도 같은 키가 영향을 받습니다. 실습 뒤 두 객체만 제거합니다.
  1. User keybindings.json 배열 안에 아래 두 객체를 이 순서대로 추가하고 저장합니다.

입력 위치 Preferences: Open Keyboard Shortcuts (JSON); User 범위. 이 내용은 settings.json이나 .vscode/keybindings.json에 넣지 않습니다.

[
  {
    "key": "ctrl+k ctrl+alt+t",
    "command": "workbench.action.tasks.terminate",
    "args": "JCOS Log Lab Target",
    "when": "taskRunning && terminalFocus && taskTerminalActive && !terminalTextSelected && !terminalFindVisible"
  },
  {
    "key": "ctrl+k ctrl+alt+t",
    "command": "workbench.action.toggleSidebarVisibility",
    "when": "terminalFocus"
  }
]
정상 결과 종료 규칙 아래에 terminalFocus 조건의 sidebar 토글 규칙이 놓입니다.

확인 기존 배열이 비었을 때만 아래 전체 배열을 사용할 수 있습니다. 기존 항목이 있으면 바깥 [ ]를 제외한 객체 두 개를 마지막 항목 뒤에 쉼표로 이어 붙입니다. 원본과 비교해 두 개만 추가됐는지 확인합니다.

실패 신호 중첩 배열·쉼표 오류·기존 객체 삭제·args label 오타입니다.

복구와 재합류 실습 추가 부분만 취소합니다. 오류가 없어지고 백업과 기존 내용이 일치하면 S06에서 다시 추가합니다.

근거: S3 S9

S07. 보호할 Guard를 실행합니다

PROCEDURE · 목적 종료 대상 밖의 Task가 살아 있는지 비교합니다.

주의·되돌리기 실무 Task는 선택하지 않습니다. 예제는 300회 출력 후 자연 종료하므로 그 전에 검사를 마칩니다.
  1. Tasks: Run Task에서 JCOS Log Lab Guard를 한 번 선택합니다.

입력 위치 Command Palette → Task 선택; 출력은 Guard Task Terminal.

예상 출력 형식:
LOG_LAB_GUARD RUN_ID=<실제 8자리 값>
LOG_LAB_GUARD HEARTBEAT=0
LOG_LAB_GUARD HEARTBEAT=1
정상 결과 HEARTBEAT 숫자가 약 1초마다 증가합니다.

확인 실제 RUN_ID와 연속된 HEARTBEAT 두 줄을 로컬 메모에 기록합니다. <실제 8자리 값>은 설명용 Placeholder이며 입력하지 않습니다.

실패 신호 출력 marker가 다르거나 Task가 곧 끝나거나 중복 실행입니다.

복구와 재합류 해당 연습 label만 Tasks: Terminate Task로 정리합니다. 오류 원문을 보존하고 S04 정의를 확인한 뒤 S07에서 재실행합니다.

근거: S5

S08. 종료할 Target을 실행합니다

PROCEDURE · 목적 두 프로세스의 비교 기준을 준비합니다.

주의·되돌리기 Human Gate: 종료 시험 전에 Target·Guard 두 label를 확인합니다. Guard만 실행 중이면 종료 shortcut을 시험하지 않습니다.
  1. Tasks: Run Task에서 JCOS Log Lab Target을 한 번 선택합니다.

입력 위치 Command Palette → Task 선택; 출력은 Target Task Terminal.

예상 출력 형식:
LOG_LAB_TARGET RUN_ID=<실제 8자리 값>
LOG_LAB_TARGET HEARTBEAT=0
정상 결과 Target과 Guard가 각각 실행 중입니다.

확인 두 Terminal의 marker와 RUN_ID를 구별하고 각 출력이 증가하는지 확인합니다.

실패 신호 하나가 종료됐거나 다른 label이 실행됐습니다.

복구와 재합류 연습 Task 상태를 확인하고 빠진 label만 실행합니다. 알 수 없는 Task는 종료하지 않습니다. 정상 두 Task 상태에서 S09로 재합류합니다.

근거: S5 S11

S09. 단축키 진단 Logging을 켭니다

PROCEDURE · 목적 실제 매칭 과정을 기록합니다.

주의·되돌리기 로그에는 입력과 환경 정보가 남을 수 있습니다. 로컬에만 보존하고 실습 종료 후 같은 Toggle 명령을 한 번 실행해 Logging을 끕니다.
  1. Developer: Toggle Keyboard Shortcuts Troubleshooting을 한 번 실행합니다.

입력 위치 Command Palette; 명령 ID workbench.action.toggleKeybindingsLog.

기록 위치: Output 패널의 현재 Window 로그
메모: Logging을 켠 시각
정상 결과 Output에서 Window 로그가 열립니다.

확인 진단 키 입력 뒤 [KeybindingService] 줄이 추가되는지 S10에서 확인합니다. 켜짐을 확인하기 위해 같은 Toggle 명령을 반복하지 않습니다.

실패 신호 Output이 열리지 않거나 시도 후 로그가 없습니다.

복구와 재합류 상태를 모르면 먼저 임의 추가 변경을 멈춥니다. 기록 시각·현재 Output 채널을 확인하고 문제 해결의 로그 없음 경로로 이동합니다. 확인 후 S09 재합류입니다.

근거: S7

S10. 동일 chord를 한 번 눌러 충돌을 재현합니다

PROCEDURE · 목적 Received와 실제 선택 명령을 연결합니다.

주의·되돌리기 위 로그의 후보 수·시각·키 표현은 작성자의 실제 값입니다. 독자 환경에서 숫자가 달라도 실패로 단정하지 않습니다. 부가 Soft dispatch 검사보다 최종 matched·Invoking 묶음을 확인합니다.
  1. Target Task Terminal 본문 입력 위치에 포커스를 두고 Ctrl+K를 누른 뒤 모두 놓고 Ctrl+Alt+T를 누릅니다.

입력 위치 Target Task Terminal 본문. 선택한 텍스트와 Find가 없는 상태이며 Target·Guard가 모두 실행 중이어야 합니다.

실제 관찰한 수정 전 원문 발췌:
2026-09-14 19:08:55.193 [info] [KeybindingService]: / Received  keydown event - modifiers: [ctrl,alt], code: KeyT, keyCode: 84, key: t
2026-09-14 19:08:55.194 [info] [KeybindingService]: | Converted keydown event - modifiers: [ctrl,alt], code: KeyT, keyCode: 50 ('T')
2026-09-14 19:08:55.196 [info] [KeybindingService]: | Resolving ctrl+K,ctrl+alt+T
2026-09-14 19:08:55.197 [info] [KeybindingService]: \ From 2 keybinding entries, matched workbench.action.toggleSidebarVisibility, when: terminalFocus, source: user.
2026-09-14 19:08:55.198 [info] [KeybindingService]: + Invoking command workbench.action.toggleSidebarVisibility.
2026-09-14 19:08:55.248 [info] [KeybindingService]: / Soft dispatching keyboard event
정상 결과 sidebar 표시가 바뀌고 matched가 workbench.action.toggleSidebarVisibility, source: user로 기록됩니다.

확인 종료 시험 시각에 대응하는 KeyK·KeyT 입력과 Resolving ctrl+K,ctrl+alt+T를 찾습니다. Target 출력도 계속 증가합니다. 첫 키의 awaiting은 호출 완료가 아닙니다.

실패 신호 다른 명령 호출, Target 조기 종료, chord의 두 번째 입력 누락입니다.

복구와 재합류 실제 로그를 그대로 보존하고 S05·S06의 key와 배열 순서를 확인합니다. 예상 밖 명령이면 추가 키 시험을 중단합니다. 두 Task가 정상인 상태로 S10에서 재합류합니다.

근거: S8 S9 S10

S11. 수정 전 로그 원문을 파일로 보존합니다

PROCEDURE · 목적 비교 기준을 잃지 않습니다.

주의·되돌리기 외부 공유·업로드는 하지 않습니다. 원문은 보존하고 개인정보를 가릴 공유본은 필요할 때 별도 파일로 만듭니다.
  1. Output의 해당 시도 구간을 복사해 연습 폴더 diagnosis-before.log에 저장합니다.

입력 위치 VS Code Output → 별도 텍스트 파일.

diagnosis-before.log: KeyK 입력부터 마지막 Invoking까지 시간·내용 그대로
diagnosis-notes.md: 입력 위치·Task label·예상 명령·관찰 명령을 별도로 기록
정상 결과 원문 파일과 Output의 해당 구간이 일치합니다.

확인 복사 후 저장 파일을 다시 열고 시각·KeyT·matched·when·source·Invoking 줄이 빠지지 않았는지 대조합니다.

실패 신호 줄이 잘렸거나 해석 문구를 원문에 섞었거나 로그를 지웠습니다.

복구와 재합류 Output에서 다시 복사합니다. 원본이 사라졌으면 상태를 확인한 뒤 S10를 한 번 재현합니다. 보존 완료 후 S12로 이동합니다.

근거: S7 S8

S12. 승리한 User 규칙의 when 하나만 수정합니다

PROCEDURE · 목적 확인된 충돌 원인을 최소 변경으로 해결합니다.

주의·되돌리기 Human Gate: 원문과 해당 User 객체를 연결한 후 수정합니다. 조건을 지우거나 종료 규칙을 무조건 활성화하지 않습니다. 원복은 이 문자열을 terminalFocus로 되돌리는 것입니다.
  1. User keybindings.json에서 아래쪽 sidebar 토글 객체의 when만 terminalFocus에서 editorTextFocus로 바꾸고 저장합니다.

입력 위치 현재 Profile의 User keybindings.json; S06에서 추가한 두 번째 객체.

{
  "key": "ctrl+k ctrl+alt+t",
  "command": "workbench.action.toggleSidebarVisibility",
  "when": "editorTextFocus"
}
정상 결과 Task 종료 객체는 그대로이고 sidebar 객체의 when 문자열 하나만 바뀝니다.

확인 수정 전 source: user·matched 명령·when: terminalFocus를 두 번째 객체와 대조한 뒤 백업/수정 전 내용과 비교합니다. 기존 종료 조건과 args는 보존합니다.

실패 신호 command·key·args까지 바뀌었거나 다른 기존 규칙을 수정했습니다.

복구와 재합류 추가 변경만 취소하고 두 실습 객체를 식별합니다. 원인을 특정할 수 없으면 UNKNOWN으로 메모하고 중단합니다. 한 문자열 변경을 확인한 뒤 S13로 재합류합니다.

근거: S4 S9

S13. 같은 위치에서 재시험하고 수정 후 로그를 저장합니다

PROCEDURE · 목적 수정 효과를 동일 조건으로 확인합니다.

주의·되돌리기 이 단계는 Target 프로세스를 종료합니다. 출력 외에 보호할 데이터가 없는 연습 Task인지 독자가 직접 확인해야 합니다. 재실행은 S08에서 명시적으로 합니다.
  1. Target·Guard 실행을 확인한 뒤 S10와 같은 Terminal 위치에서 chord를 한 번 누르고 해당 로그를 diagnosis-after.log로 저장합니다.

입력 위치 Target Task Terminal 본문 → Output → 연습 폴더 diagnosis-after.log.

실제 관찰한 수정 후 원문 발췌:
2026-09-14 19:09:49.338 [info] [KeybindingService]: / Received  keydown event - modifiers: [ctrl,alt], code: KeyT, keyCode: 84, key: t
2026-09-14 19:09:49.342 [info] [KeybindingService]: | Converted keydown event - modifiers: [ctrl,alt], code: KeyT, keyCode: 50 ('T')
2026-09-14 19:09:49.345 [info] [KeybindingService]: | Resolving ctrl+K,ctrl+alt+T
2026-09-14 19:09:49.347 [info] [KeybindingService]: \ From 2 keybinding entries, matched workbench.action.tasks.terminate, when: taskRunning && taskTerminalActive && terminalFocus && !terminalFindVisible && !terminalTextSelected, source: user.
2026-09-14 19:09:49.348 [info] [KeybindingService]: + Invoking command workbench.action.tasks.terminate.
2026-09-14 19:09:49.400 [info] [KeybindingService]: / Soft dispatching keyboard event
정상 결과 matched가 workbench.action.tasks.terminate, source: user이고 Invoking command도 같은 명령입니다.

확인 수정 전후 Received·Converted·Resolving은 같은 chord인지, matched 명령이 바뀌었는지 비교합니다. when의 항목 순서가 달라도 논리 의미가 같은지 확인합니다. args는 JSON에서 JCOS Log Lab Target인지 따로 확인합니다.

실패 신호 여전히 sidebar 매칭, no when clauses matched, 종료 대상 선택창 또는 예상 밖 명령입니다.

복구와 재합류 선택창이 나오면 Esc로 취소하고 Target 실행·label·args를 확인합니다. All Running Tasks는 선택하지 않습니다. 원문 보존 후 S08 또는 S12에서 복구하고 S13로 재합류합니다.

근거: S8 S9 S10 S11

S14. 로그와 독립된 Task 결과를 확인합니다

PROCEDURE · 목적 명령 호출을 실제 종료 성공과 구별합니다.

주의·되돌리기 작성자 PID는 독자에게 적용되지 않습니다. PID를 복사해 종료 명령을 실행하지 않습니다. 종료 코드가 0이 아니어도 강제 종료 자체와 명령 오류를 구별합니다.
  1. Terminal 출력과 Tasks: Show Running Tasks를 사용해 Target 종료·Guard 지속 실행을 교차 확인합니다.

입력 위치 Target/Guard Task Terminal 및 Command Palette.

관찰 기록: Target 마지막 HEARTBEAT·Guard 연속 HEARTBEAT·Guard RUN_ID
작성자 프로세스 증거: Target PID 25044 종료, Guard PID 29368 유지
정상 결과 Target에 새 HEARTBEAT가 없고 Guard는 같은 실행으로 계속 증가합니다.

확인 Target의 마지막 숫자를 기록하고 최소 3초 뒤 새 출력이 없는지 확인합니다. 같은 시간 Guard는 증가해야 합니다. Show Running Tasks에서 남아 있는 연습 Task가 Guard인지 확인합니다. Terminal 탭 존재만으로 실행 여부를 판단하지 않습니다.

실패 신호 Target이 계속 출력하거나 새 RUN_ID로 다시 실행됐거나 Guard도 멈췄습니다.

복구와 재합류 현재 시각·출력·로그를 보존합니다. 자동 재시작·300초 자연 종료·다른 규칙을 구별하고 확인 못 하면 UNKNOWN으로 중단합니다. 연습 상태 복구 후 S13→S14으로 재검증합니다.

근거: S11 S12

S15. Guard만 종료합니다

PROCEDURE · 목적 보호한 연습 프로세스를 정리합니다.

주의·되돌리기 Human Gate: 실행 중 label가 연습 Guard인지 확인한 후 선택합니다. All Running Tasks로 일괄 종료하지 않습니다. 연습 Guard의 재실행은 S07에서 직접 선택합니다.
  1. Tasks: Terminate Task에서 JCOS Log Lab Guard만 선택해 종료합니다.

입력 위치 Command Palette → 종료 대상 선택창.

종료할 label: JCOS Log Lab Guard
정리 전 보호 대상: 다른 모든 Task
정상 결과 연습 Task가 모두 끝납니다.

확인 Guard에 최소 3초 동안 새 HEARTBEAT가 없고 Tasks: Show Running Tasks에서 두 연습 label가 실행 중이 아닌지 확인합니다.

실패 신호 다른 label 선택·출력 지속·실무 Task 종료입니다.

복구와 재합류 선택창은 Esc로 취소합니다. 이미 종료된 실무 작업은 임의로 재시작하지 말고 상태를 보존합니다. 연습 label가 맞는 경우에만 다시 종료하며 S15에서 재검사합니다.

근거: S7 S11

S16. 실습 User 규칙 두 개를 제거합니다

PROCEDURE · 목적 다른 폴더에 실습 단축키가 남지 않게 합니다.

주의·되돌리기 Human Gate: 제거할 두 객체를 식별한 뒤 수정합니다. 전체 배열을 삭제하지 않습니다. 백업과 원문 파일은 그대로 보관합니다.
  1. User keybindings.json에서 이번에 추가한 두 객체만 제거하고 저장합니다.

입력 위치 현재 Profile의 User keybindings.json.

보존할 파일: keybindings-before.jsonc
제거할 객체: 종료 Target 규칙·sidebar 토글 실습 규칙
정상 결과 기존 User 단축키가 남고 두 실습 객체만 없어집니다.

확인 S03 백업과 대조합니다. 실습 도중 다른 User 변경을 했다면 그 변경은 보존합니다.

실패 신호 기존 규칙 누락·배열 문법 오류·실습 객체 잔존입니다.

복구와 재합류 백업 기준으로 누락된 기존 규칙만 복구합니다. 다른 변경이 전혀 없을 때만 전체 백업 복원을 사용합니다. S16에서 재검사 후 S17로 이동합니다.

근거: S3

S17. 진단 Logging을 끕니다

PROCEDURE · 목적 이후 입력이 계속 기록되지 않게 합니다.

주의·되돌리기 로컬 원문은 삭제·외부 전송하지 않습니다. 연습 폴더는 보관할 수 있습니다. 다시 진단할 때는 S09에서 명시적으로 켭니다.
  1. Developer: Toggle Keyboard Shortcuts Troubleshooting을 한 번 실행합니다.

입력 위치 Command Palette; S09에서 켠 진단 Logging.

보관 파일: diagnosis-before.log·diagnosis-after.log·diagnosis-notes.md
정상 결과 새 [KeybindingService] 기록 추가가 멈춥니다.

확인 알려진 안전한 키 입력 뒤 진단 줄이 새로 추가되지 않는지 확인합니다. Toggle 명령을 수차례 반복하지 않습니다.

실패 신호 진단 줄이 계속 생기거나 현재 상태가 불명확합니다.

복구와 재합류 현재 로그 시각을 보존하고 안전한 키로 상태를 확인합니다. 활성임이 확인될 때만 Toggle을 한 번 더 실행합니다. S17에서 재검사합니다.

근거: S7

4. 완료 확인하기

완료 확인은 JSON 편집 화면 밖의 로그와 실행 결과를 함께 사용합니다.

  • 동일한 전체 chord와 Terminal 입력 위치로 비교한 수정 전·후 원문 파일이 있습니다.
  • 수정 전 matched는 sidebar 토글, 수정 후 matched와 Invoking은 tasks.terminate입니다. 둘 다 User 출처이며 다른 command 호출과 혼동하지 않았습니다.
  • 수정한 것은 sidebar 객체의 when 하나입니다. 종료 객체의 key·command·args·기존 다섯 조건은 유지됐습니다.
  • Target 새 출력은 멈췄고 Guard는 같은 RUN_ID로 HEARTBEAT가 증가했습니다. 명령 호출만 보고 완료로 판단하지 않았습니다.
  • Guard와 실습 User 규칙 두 개를 정리하고 Logging을 껐습니다. 기존 단축키와 로컬 원문은 보존됐습니다.

작성자 검증: 실제 설치된 VS Code 1.137.0을 별도 user-data-dir과 확장 비활성 상태로 실행했습니다. 동일 예제 command·args로 두 Task를 시작하고 CDP 키 이벤트로 수정 전·후 chord를 전달했습니다. Target PID 25044는 사라졌고 Guard PID 29368은 유지됐으며, Guard HEARTBEAT는 66→87로 증가했습니다. 독자의 User 설정은 변경하지 않았습니다.

UNCONFIRMED: 독자 PC의 물리 키 전달, IME·키보드 배열·확장·동기화·기존 Profile에 따른 결과는 이 격리 시험으로 확정할 수 없습니다. 추가 Editor-focus 시험에서는 조건 불일치 로그가 나왔으므로 editorTextFocus의 실제 UI 재활성화는 검증됐다고 주장하지 않습니다. 이 글의 완료 기준은 같은 Task Terminal에서 종료 매칭을 복구하는 것입니다. 독자는 위 관찰로 자기 환경을 다시 확인합니다.

5. 문제가 생겼다면

원하는 키의 Received 줄이 없습니다

먼저 확인 Logging을 켠 시각·Window 채널·VS Code 창·입력 위치를 확인합니다. 다른 키는 기록되는지 구별합니다.

복구 원문과 환경을 보존합니다. Windows나 IME에서 입력이 소비됐다고 단정하지 않습니다. Terminal Advanced의 chord·키 전달 경로를 읽고 현재 설정부터 확인합니다. 설정을 한꺼번에 초기화하지 않습니다.

재합류 원인 UNKNOWN이면 중단; 수신이 확인되면 S09→S10

근거: S6 S8

awaiting만 있고 최종 matched가 없습니다

먼저 확인 두 조합을 차례로 눌렀는지, 첫 조합과 두 번째 조합 사이에 포커스가 바뀌었는지 확인합니다.

복구 키를 모두 놓고 같은 Terminal 본문에서 한 번 다시 시도합니다. 부분 chord의 후보를 최종 실행 명령으로 오해하지 않습니다.

재합류 두 Task 상태를 확인한 뒤 S10

근거: S10

matched가 예상과 다르지만 source는 user입니다

먼저 확인 같은 전체 chord의 User 객체·배열 순서·when을 대조합니다. source만으로 args나 파일 행 번호를 알 수는 없습니다.

복구 원문을 보존한 뒤 S06의 두 번째 객체인지 확인합니다. 여러 같은 명령 객체가 있어 식별이 안 되면 임의 수정하지 않고 UNKNOWN으로 중단합니다.

재합류 대상 객체가 입증되면 S12

근거: S9

no when clauses matched the context가 보입니다

먼저 확인 이 줄이 최종 실제 dispatch인지 부가 Soft dispatch인지 구별합니다. Task 실행·Terminal 입력 포커스·텍스트 선택·Find 표시 상태를 점검합니다.

복구 선택·Find를 닫고 입력 위치를 다시 확인합니다. when 전체를 삭제하지 않습니다. Editor에서의 불일치만으로 Terminal 수리를 실패 판정하지 않습니다.

재합류 정상 연습 상태에서 S13

근거: S4 S9

Invoking은 terminate인데 Target이 안 멈추거나 선택창이 뜹니다

먼저 확인 로그의 command만으로 args 성공을 보장하지 않습니다. Target 실행 여부와 JSON의 args·label 정확한 일치를 확인합니다.

복구 선택창은 Esc로 취소합니다. terminateAll 인수나 All Running Tasks로 우회하지 않습니다. Target을 명시적으로 다시 실행한 뒤 같은 상태에서 재시험합니다.

재합류 S08→S13→S14

근거: S11

두 Task가 모두 끝났습니다

먼저 확인 300초 자연 종료, 사용자의 일괄 종료, 다른 명령 호출을 구별합니다. 실제 종료 시각과 원문을 보존합니다.

복구 프로세스 원인을 확인 못 하면 UNKNOWN입니다. 다른 실무 Task를 재시작하지 말고 연습 label 두 개만 새로 실행합니다.

재합류 S07→S08→S13→S14; 종료 후 S15

근거: S5 S11

원인을 입증하지 못하면 UNKNOWN으로 기록하고 원문을 보존한 채 중단합니다.

6. 핵심 정리와 공식 자료

Task 단축키 진단은 Received → Resolving/matched → Invoking → 실제 Task 상태 순서로 확인합니다. 충돌 원인을 입증하는 기준은 수정 전·후 원문과 한 문자열 변경입니다. 후보 숫자나 호출 로그 하나만으로 성공을 선언하지 않습니다. 기존 선택·Find 잠금과 보호할 User 규칙을 유지하고, 완료 후 실습 영향은 원복합니다.

공식 자료

2026-09-14 KST 접근 확인. 문서는 현재 내용, 소스는 Stable commit 고정이며 독자 환경 결과는 재확인이 필요합니다.

다음 편 예고 커맨드 팔레트 47부 — Task 단축키를 키보드의 물리 키 위치로 고정하기. 키보드 배열과 물리 키 위치를 구별해 Task 단축키를 유지합니다.
반응형
이 글이 유용했다면 링크를 공유해 보세요.