「중도 입사한 시각장애 직원이 핵심 수주 앱을 스크린 리더로 쓸 수 없다. 웹 브라우저와 메일은 문제없이 쓰는데, 우리 업무 앱만 읽기가 제대로 되지 않는다. 뭔가 할 수 있을까?」── 고객 IT 부서에서 이런 상담이 늘고 있습니다.
배경 하나는 법 체계입니다. 2021년 개정 장애인차별해소법이 2024년 4월 1일 시행되어, 장애인에 대한 「합리적 배려의 제공」이 사업자에게도 의무가 되었습니다.1 또한 서두와 같은 직원–회사 관계(고용 분야)는 장애인고용촉진법의 영역이며, 2016년 4월부터 고용주에게 합리적 배려를 의무로 두고 있습니다.2 「접근성은 웹사이트 주제이고 사내 Windows 앱과는 무관하다」는 생각은, 법적으로도 실무적으로도 더 이상 성립하지 않습니다.
한편 개발 현장에서는 「무엇을 해야 할지 모르겠다」가 솔직한 자리입니다. Windows 데스크톱 앱의 접근성은 웹보다 정보가 적고, 사후에 마법처럼 해결하는 방법은 없습니다. 비관할 필요도 없습니다. 스크린 리더가 앱을 읽는 메커니즘(UI Automation)을 이해하고 이름, 키보드, 색의 기본을 받아들이면, 업무 앱의 사용성은 크게 좋아집니다. 그리고 그 상당수는 장애 유무와 관계없이 모든 사용자의 생산성을 올리는 개선입니다.
일본 업무 앱 개발자와 IT 담당자를 대상으로, 이 글은 법 체계와 기준의 최소 정리부터 UI Automation의 메커니즘, WinForms/WPF 구현, 키보드 조작, 색과 대비, 검증 도구, 현실적인 우선순위 정하기까지를 한 번에 이습니다.
flowchart TB
accTitle: 이 글의 흐름
accDescr: 법 체계와 기준의 정리부터 UI Automation의 메커니즘, WinForms와 WPF 구현, 키보드 조작, 색과 대비, 검증 도구, 우선순위 정하기까지를 차례로 잇는 이 글의 구조
law["법 체계와 기준의 정리"] --> uia["UI Automation의 메커니즘"]
uia --> impl["WinForms/WPF 구현"]
impl --> kb["키보드 조작"]
kb --> color["색과 대비"]
color --> verify["검증 도구"]
verify --> prio["우선순위 정하기"]
그림 1: 이 글은 법 체계에서 메커니즘, 구현, 검증, 우선순위까지를 하나의 흐름으로 잇는다.
1. 먼저 결론
- 합리적 배려의 제공은 2024년 4월 1일부터 사업자에게도 의무입니다. 장애인이 장벽 제거의 의사를 나타내면, 과중한 부담이 되지 않는 범위의 대응이 요구됩니다. 고용 분야는 장애인고용촉진법의 영역이며, 2016년 4월부터 고용주 의무입니다.12
- 합리적 배려는 「개별 요청에 건설적 대화로 대응하는」 과정이며, 앱을 미리 쓰기 쉽게 만드는 것은 「환경 정비」(노력 의무)입니다. 완벽한 사전 대응이 의무가 아니며, 중요한 것은 대화를 일방적으로 거부하지 않는 것입니다.1
- 접근성의 기술 기준은 WCAG(JIS X 8341-3:2016)에 모여 있습니다. JIS X 8341-3:2016은 WCAG 2.0과 같은 내용의 대응 규격이며, W3C의 WCAG2ICT가 비웹 소프트웨어에 적용하는 안내를 줍니다. 데스크톱 앱도 같은 생각으로 점검할 수 있습니다.34
- 스크린 리더는 UI Automation(UIA)을 통해 앱을 읽습니다. UIA 트리의 각 요소가 가진 Name, ControlType 같은 속성과 Invoke, Value, SelectionItem 같은 컨트롤 패턴이 알림과 조작의 재료입니다.5
- Name이 비어 있는 단추는 「단추」로만 알림됩니다. 최우선 수정은 이름 붙이기입니다. WinForms는 AccessibleName과 탭 순서로 Label을 연결하는 것, WPF는 AutomationProperties.Name/LabeledBy입니다.67
- 모든 기능을 키보드만으로 도달할 수 있는 것은 WCAG 성공 기준(2.1.1)이며, 동시에 숙련 조작자의 입력 속도 그 자체입니다. 탭 순서, 액세스 키, 포커스 표시를 갖추는 것은 모든 사용자의 효율로 직결됩니다.8
- 텍스트 대비비 4.5:1 이상을 가이드로 삼고, 색만으로 정보를 전하지 마십시오. 대비 테마(고대비)에서는 하드코딩 색이 아니라 시스템 색을 존중합니다.89
- 검증은 Accessibility Insights for Windows의 FastPass와 스크린 리더 실습을 조합합니다. 같은 UIA 기반 위에 있으므로, 이 작업은 FlaUI 같은 UI 자동 테스트 자산과도 서로 이득이 됩니다.10
- 모든 화면을 한꺼번에 고칠 필요는 없습니다. 현실적인 순서는 (1) 그 사용자가 쓰는 화면부터, (2) 신규 개발은 기준에 맞추고, (3) 공유 컨트롤을 고쳐 옆으로 펼칩니다.
한 문장으로 접근성 대응은 「UIA 트리에 올바른 이름과 조작을 노출하고, 키보드와 색의 기본을 지키는 것」입니다.
2. 법 체계와 기준의 정리 ── 「의무가 된 것」이 바꾼 점
2.1. 장애인차별해소법 ── 2024년 4월부터 사업자에게도 합리적 배려가 의무
장애인차별해소법은 행정기관과 사업자의 장애인에 대한 「부당한 차별적 취급」을 금지하고 「합리적 배려의 제공」을 요구하는 법률입니다. 2021년(레이와 3년) 개정에서 노력 의무이던 사업자의 합리적 배려 제공이 의무가 되었고, 개정법은 2024년 4월 1일(레이와 6년) 시행되었습니다.1
내각부 리플릿에 따르면, 합리적 배려의 제공은 장애인이 사회의 장벽을 제거하기 위해 어떤 대응이 필요하다는 의사를 나타냈을 때, 과중한 부담이 되지 않는 범위에서 대응하는 것입니다. 그리고 내용은 장애 특성, 장면, 상황에 따라 다르므로, 장애인과 사업자가 대화를 쌓아 대응을 함께 생각하는 「건설적 대화」가 강조됩니다. 건설적 대화를 일방적으로 거부하는 것은 합리적 배려 제공 의무 위반이 될 수 있다고 명시되어 있습니다.1
여기서 실무적으로 중요한 구분은 둘입니다.
- 「미리 모든 것을 갖추는 것」이 의무가 된 것이 아닙니다. 불특정 다수의 장애인을 향한 사전 개선 조치── 매뉴얼 재검토와 연수 같은 소프트 측, 시설 배리어 프리 같은 하드 측──은 「환경 정비」라 불리며, 이것은 노력 의무입니다.1 업무 앱을 미리 스크린 리더로 쓸 수 있는 상태로 두는 것은 환경 정비의 노력으로 생각할 수 있습니다. 환경 정비가 더 나아갈수록, 개별 합리적 배려를 제공하는 부담은 가벼워집니다.
- 고용 분야는 장애인차별해소법이 아니라 장애인고용촉진법의 영역입니다. 같은 리플릿도 고용과 근무는 장애인고용촉진법의 규정을 따른다고 말합니다.1 그리고 그 법은 2016년 4월(헤이세이 28년) 시행 개정으로 고용에서의 장애 차별 금지와, 과중한 부담이 되지 않는 범위의 합리적 배려 제공을 고용주에게 의무로 두었습니다.2 「직원이 업무 앱을 쓸 수 없다」는 서두의 상담은, 사실 2024년보다 훨씬 전부터 의무의 영역이었습니다.
flowchart TB
accTitle: 합리적 배려와 환경 정비의 위치
accDescr: 일반 사업자와 장애인의 관계는 장애인차별해소법의 영역이며 개별 요청에 건설적 대화로 대응하는 합리적 배려의 제공은 2024년 4월부터 의무이고, 고용 분야는 2016년 4월부터 장애인고용촉진법 아래 고용주 의무이며, 앱을 미리 쓰기 쉽게 만드는 것은 노력 의무인 환경 정비이다
scene{"어느 장면인가?"}
scene -->|사업 + 장애| kaisho["차별해소법"]
scene -->|고용 / 근무| koyou["고용촉진법"]
kaisho --> moushide["대화를 통한 요청"]
moushide --> hairyo["배려를 제공"]
hairyo -.-> hairyoN["2024년부터 의무"]
koyou --> koyougimu["배려를 제공"]
koyougimu -.-> koyouN["2016년부터 의무"]
kaisho -.-> kankyo["미리 쓰기 쉬운 앱"]
kankyo -.-> kankyoN["환경 정비"]
kankyoN -.-> kankyoN2["노력 의무"]
kankyo -.-> moushide
그림 2: 적용 법률은 장면으로 갈리고, 합리적 배려는 의무이며 사전 수정은 노력 의무인 환경 정비이다.
개별 사안이 법에서 어떻게 다루어지는지는 상황에 따릅니다. 이 글은 법적 해석에 들어가지 않고, 대응이 요청되었을 때 엔지니어가 할 수 있는 일의 관점에서 진행합니다. 1차 정보는 내각부와 후생노동성 자료를 참조하십시오.12
2.2. JIS X 8341-3과 WCAG ── 「웹 기준」은 소프트웨어에도 이어진다
기술 기준 측은 JIS X 8341-3:2016에 모여 있습니다. 이 규격은 ISO/IEC 40500:2012의 대응 규격이며, 규격 본문은 W3C의 WCAG 2.0과 같은 내용입니다.3 「접근성 대응」이 구체적으로 무엇으로 이루어지는지 알고 싶으면 WCAG 성공 기준(지금은 WCAG 2.1/2.2로 확장)을 읽는 것이 가장 짧고, WAIC의 일본어 번역도 공개되어 있습니다.8
「WCAG는 웹 콘텐츠의 기준인가?」라는 질문은 타당하지만, W3C는 WCAG2ICT(Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies)라는 Group Note에서 WCAG 2.0/2.1/2.2 성공 기준을 비웹 문서와 소프트웨어에 어떻게 적용하는지를 정리했습니다.4 즉 「텍스트 대체」, 「대비」, 「키보드 조작」, 「색만이 수단이 아니다」라는 생각을 Windows 데스크톱 앱에도 웹과 같은 틀로 적용할 수 있습니다. 이 글의 3장 이후는 그 생각을 구체적인 WinForms/WPF 구현으로 내립니다.
flowchart TB
accTitle: JIS X 8341-3과 WCAG의 관계
accDescr: JIS X 8341-3:2016은 WCAG 2.0과 같은 내용의 대응 규격이며, WCAG2ICT가 WCAG 성공 기준을 비웹 소프트웨어에 적용하는 법을 보여 주므로 Windows 데스크톱 앱을 같은 틀로 점검할 수 있다
wcag["WCAG 2.0(W3C)"] ---|같은 내용의 대응 규격| jis["JIS X 8341-3:2016"]
wcag --> ict["WCAG2ICT"]
ict --> soft["비웹 소프트웨어에 적용"]
soft --> app["Windows 데스크톱 앱"]
그림 3: JIS X 8341-3:2016은 WCAG 2.0의 대응 규격이며, WCAG2ICT가 같은 기준을 데스크톱 앱으로 확장한다.
3. 보조 기술이 앱을 읽는 방식 ── UI Automation의 삼위일체
3.1. UIA 트리, 속성, 컨트롤 패턴
Windows에는 UI Automation(UIA)이라는 접근성 기반이 내장되어 있습니다. UIA는 스크린 리더 같은 보조 기술이 UI 정보를 얻고 표준 입력 이외의 수단으로 UI를 조작하게 하는 메커니즘이며, 앱 측(프로바이더)과 보조 기술 측(클라이언트)을 중개합니다.5
UIA의 세계는 다음 삼위일체로 이해할 수 있습니다.5
| 요소 | 역할 | 대표 예 |
|---|---|---|
| UIA 트리 | 데스크톱을 루트로 창 → 컨트롤로 이어지는 트리. 보조 기술은 이 트리를 걸어 UI를 파악한다 | 창, 창살, 단추, 편집 상자 |
| 속성 | 각 요소의 성격을 나타내는 값 | Name(목적), ControlType(종류), AutomationId(식별자), IsEnabled, IsKeyboardFocusable |
| 컨트롤 패턴 | 종류별 「할 수 있는 조작」의 어휘 | Invoke(누르기), Value(값 읽기/쓰기), SelectionItem(선택), Toggle(켜기/끄기), ExpandCollapse(펼치기/접기) |
스크린 리더가 단추에 포커스할 때 「주문 확정 단추」라는 알림은, 대략 Name + 컨트롤 종류의 조합입니다. 사용자가 「실행」조작을 하면 보조 기술은 Invoke 패턴으로 그 단추를 누릅니다. 즉 Name과 패턴이 올바르게 노출되면 읽고 조작할 수 있고, 노출되지 않으면 화면에 보여도 없는 것과 같습니다.
flowchart TB
accTitle: UI Automation의 삼위일체
accDescr: 앱은 프로바이더로서 UIA 트리에 각 요소의 속성과 컨트롤 패턴을 노출하고, 스크린 리더는 클라이언트로서 Name과 ControlType을 알리며 Invoke 같은 패턴으로 조작한다
app["앱(프로바이더)"] --> tree["UIA 트리"]
tree --> prop["속성(Name, ControlType 등)"]
tree --> pat["패턴(Invoke, Value 등)"]
sr["스크린 리더(클라이언트)"] -->|알린다| prop
sr -->|조작한다| pat
그림 4: 스크린 리더는 앱이 UIA 트리에 노출한 속성과 패턴을 알림과 조작에 쓴다.
3.2. 스크린 리더는 UIA 클라이언트이다
Windows에서 쓰이는 주요 스크린 리더에는 Windows 내장의 내레이터, 무료 오픈 소스인 NVDA,11 일본에서 널리 쓰이는 상용 PC-Talker가 있습니다. 알림 스타일은 서로 다르지만, 데스크톱 앱 UI를 읽는 주 경로는 어느 쪽이든 UIA입니다. 그래서 앱 측 대응은 「특정 스크린 리더 지원」이 아니라 올바른 정보를 UIA에 노출하는 것에 모입니다.
flowchart TB
accTitle: 주요 스크린 리더의 공통 경로
accDescr: 앱이 UIA에 올바른 정보를 노출하면 내레이터, NVDA, PC-Talker가 모두 같은 경로로 UI를 읽을 수 있으므로, 앱 측 대응은 특정 스크린 리더를 향하지 않고 UIA에 노출하는 데 모인다
app["앱"] -->|정보를 노출| uia["UI Automation(UIA)"]
uia --> nar["내레이터"]
uia --> nvda["NVDA"]
uia --> pct["PC-Talker"]
app -.-> goal["대응은 UIA 노출에 모인다"]
그림 5: 주요 스크린 리더는 모두 UIA를 경로로 삼으므로, 앱의 대응은 UIA에 노출하는 데 모인다.
3.3. 「Name이 비어 있는 단추」는 무엇으로 알림되는가?
구체적인 예 하나. 도구 모음에 플로피 디스크 아이콘만 표시하는 저장 단추가 있다고 합시다. 시각 사용자에게는 아이콘이 의미를 전하지만, Name을 비워 두면 스크린 리더는 이 단추를 「단추」로만 알립니다. 옆의 「열기」와 「인쇄」가 같으면, 사용자는 「단추, 단추, 단추」만 듣고 어느 것인지 알 수단이 없습니다. Microsoft의 접근성 수정 가이드도 Name이 없는 단추, 「Image」로만 알림되는 이미지를 사용자의 작업을 멈추는 대표 문제로 꼽습니다.7
다행히 WinForms와 WPF 표준 컨트롤은 처음부터 UIA 지원이 있고, 많은 경우 Name은 텍스트나 레이블에서 자동으로 정해집니다. 깨지는 것은 보통 (1) 아이콘만 있어 이름의 재료가 없거나, (2) 레이블과의 연결이 없거나, (3) 사용자 지정 그리기가 UIA 트리에 정보를 올리지 않는 경우입니다. 다음 두 장은 프레임워크별로 고치는 법을 봅니다.
flowchart TB
accTitle: 알림이 깨지는 세 가지 전형
accDescr: 알림은 아이콘만 있어 이름의 재료가 없을 때, 레이블과의 연결이 없을 때, 사용자 지정 그리기가 UIA 트리에 정보를 올리지 않을 때 깨지고, 단추로만 알림되는 결과가 된다
c1["아이콘만, 재료 없음"] --> broken["Name이 비게 된다"]
c2["레이블과의 연결 없음"] --> broken
c3["사용자 지정 그리기가 정보를 내지 않음"] --> broken
broken --> result["단추로만 알림"]
그림 6: 알림이 깨지는 것은 보통 이름의 재료 부족, 연결 부족, 사용자 지정 그리기 세 패턴 중 하나로 귀결된다.
4. WinForms 구현 ── AccessibleName과 탭 순서
4.1. Text가 자동으로 Name이 되는 컨트롤과 되지 않는 컨트롤
WinForms에서 Button이나 CheckBox처럼 텍스트를 표시하는 컨트롤은 Text 속성 값을 UIA Name으로 씁니다. 반면 ComboBox, ListBox, ListView, PictureBox, ProgressBar, TabControl, TextBox, TreeView 등은 Text를 Name으로 만들지 않습니다. 이들은 다른 수단으로 이름이 필요합니다.6
가장 유지보수하기 좋은 방법은 대상 컨트롤의 바로 앞 탭 순서에 설명 Label을 두는 것입니다. 대상 컨트롤의 TabIndex를 Label의 TabIndex 바로 다음으로 두면, 그 Label의 텍스트가 자동으로 UIA Name으로 쓰입니다. 화면에 보이는 레이블과 알림이 맞고, 문구를 두 번 관리하지 않아도 됩니다.612
Label을 둘 수 없으면 AccessibleName을 명시적으로 설정합니다. 보충 설명이 필요하면 AccessibleDescription을, 역할이 외관과 다르면 AccessibleRole도 설정할 수 있습니다.13
flowchart TB
accTitle: WinForms 컨트롤의 이름이 정해지는 방식
accDescr: Button 등은 Text가 그대로 UIA Name이 되고, TextBox처럼 Text를 재사용하지 않는 컨트롤은 바로 앞 탭 순서에 둔 Label의 텍스트가 쓰이며, Label을 둘 수 없으면 AccessibleName을 명시적으로 설정한다
ctrl["컨트롤"] --> qtext{"Text가 Name이 되는 종류인가?"}
qtext -->|예| usetext["Text가 그대로 Name"]
qtext -->|아니오| qlabel{"바로 앞 탭 순서에 Label이 있는가?"}
qlabel -->|예| uselabel["Label의 텍스트가 Name으로 쓰인다"]
qlabel -->|아니오| explicit["AccessibleName을 명시적으로 설정"]
그림 7: WinForms의 Name은 Text, 바로 앞 탭 순서의 Label, AccessibleName 순으로 정하는 방법을 고른다.
// An icon-only toolbar button: state the name for announcement explicitly
saveToolStripButton.AccessibleName = "Save";
// An image-only button: name + a supplementary explanation
btnSearchCustomer.AccessibleName = "Search customer";
btnSearchCustomer.AccessibleDescription = "Search the customer master by customer code or name";
// Set it directly on an input field where you cannot place a Label in the immediately preceding tab order
txtOrderNo.AccessibleName = "Order number";
// A PictureBox reused as a chart display: match the role to the reality as well
pictureBoxChart.AccessibleRole = AccessibleRole.Chart;
pictureBoxChart.AccessibleName = "Monthly order-count chart";
주의로, Visual Studio 속성 창에서 AccessibleName을 한 번 설정한 뒤 지우면, 빈 문자열 설정이 디자이너 파일에 남아 기본 이름 해석을 방해할 수 있습니다. 해당 줄을 디자이너 파일에서 삭제하십시오.6
flowchart TB
accTitle: 빈 문자열 AccessibleName이 남는 문제
accDescr: 속성 창에서 AccessibleName을 한 번 설정한 뒤 지우면 빈 문자열 설정이 디자이너 파일에 남아 기본 이름 해석을 방해하므로, 해당 줄을 디자이너 파일에서 삭제해 고친다
set["AccessibleName을 설정"] --> erase["속성 창에서 지움"]
erase --> remain["빈 문자열 설정이 남음"]
remain --> block["기본 이름 해석을 방해"]
block -.-> fix["디자이너 파일에서 해당 줄을 삭제"]
그림 8: 속성 창에서 지워도 빈 문자열이 남으므로, 디자이너 파일에서 해당 줄을 삭제해 고친다.
4.2. 수주 화면에서 흔히 하는 개선
업무 앱에서 실제로 자주 고치는 곳을 체크리스트로 정리합니다.
| 흔한 상태 | 문제 | 고치는 법 |
|---|---|---|
| 아이콘만인 ToolStripButton | 「단추」로만 알림 | AccessibleName을 설정 |
| TextBox 근처에 Label이 있지만 탭 순서가 흩어짐 | 입력란의 이름이 비거나 무관한 이름이 됨 | 입력란을 Label의 TabIndex 바로 다음에 둠 |
| Click으로 단추처럼 쓰는 PictureBox | 역할이 단추로 전해지지 않고 키보드로 누를 수 없음 | Button으로 바꾸거나 AccessibleRole/AccessibleName과 키보드 지원을 더함 |
| DataGridView 열 머리글이 비거나 기호만 | 셀이 알림될 때 열의 의미가 불명 | HeaderText에 의미 있는 열 이름을 설정 |
| 내용 그룹화에 Panel만 쓰고 제목이 이미지 | 어느 입력 그룹인지 알 수 없음 | GroupBox를 쓰거나 제목을 Label로 만듦 |
각각은 몇 줄의 수정이지만, 스크린 리더 사용자에게는 「쓸 수 없는 화면」과 「쓸 수 있는 화면」의 갈림입니다.
5. WPF 구현 ── AutomationProperties와 AutomationPeer
5.1. AutomationProperties.Name / LabeledBy / HelpText
WPF에서 Button처럼 Content가 문자열인 컨트롤은 그 내용을 UIA Name으로 씁니다. 아이콘만인 단추(Image 또는 Path)는 Name의 재료가 없으므로 AutomationProperties.Name으로 밝히거나, 근처에 표시 텍스트가 있으면 AutomationProperties.LabeledBy로 연결합니다.7
TextBox에는 중요한 주의가 있습니다. TextBlock의 Text는 Name으로 재사용되지만, TextBox의 Text는 UIA Value 속성 쪽에 노출되고 Name이 되지 않습니다. 입력란에는 표시 레이블 TextBlock을 LabeledBy로 연결하는 것이 첫 후보입니다. 알림과 화면 표시가 맞고, 문구를 두 번 관리하는 것도 피합니다.14
<!-- An input field: associate the display label with LabeledBy -->
<TextBlock x:Name="OrderNoLabel" Text="Order number" />
<TextBox
AutomationProperties.LabeledBy="{Binding ElementName=OrderNoLabel}"
AutomationProperties.AutomationId="OrderNoTextBox" />
<!-- An icon-only button: state the name, and a supplement if needed -->
<Button
AutomationProperties.Name="Confirm order"
AutomationProperties.HelpText="Confirm the order being entered and allocate inventory">
<Path Data="{StaticResource CheckIconGeometry}" Width="16" Height="16" />
</Button>
flowchart TB
accTitle: WPF 컨트롤의 이름이 정해지는 방식
accDescr: Content가 문자열인 컨트롤은 그 내용을 Name으로 쓰고, 그렇지 않으면 근처 표시 레이블을 LabeledBy로 연결하는 것이 첫 후보이며, 그것도 없으면 AutomationProperties.Name을 밝힌다. TextBox의 Text는 Name이 아니라 Value 쪽에 노출된다
ctrl["컨트롤"] --> qc{"Content가 문자열인가?"}
qc -->|예| auto["내용이 Name이 된다"]
qc -->|아니오| ql{"근처 표시 레이블이 있는가?"}
ql -->|예| lb["LabeledBy로 연결"]
ql -->|아니오| nm["Name을 명시적으로 설정"]
tbx["TextBox의 Text"] -.-> val["Name이 아니라 Value로 노출"]
그림 9: WPF의 Name은 Content 문자열, LabeledBy, 명시적 설정 순으로 정하고, TextBox의 Text는 Name이 되지 않는다.
Name에 들어가지 않는 보충 정보는 AutomationProperties.HelpText로 노출할 수 있습니다.7 또한 AutomationId는 UI 자동 테스트에서 요소 식별에 쓰는 식별자이므로, 화면 설계 때 명명 규칙을 정해 두면 뒤에 이득이 됩니다(「Windows 데스크톱 앱의 UI 자동 테스트」에서 깊게 다룹니다).
5.2. 사용자 지정 컨트롤에는 AutomationPeer가 필요하다
직접 그리는 사용자 지정 컨트롤은 그대로는 UIA 트리에 의미 있는 정보를 노출할 수 없습니다. WPF에서는 UIElement 파생 클래스에서 OnCreateAutomationPeer를 오버라이드하고 AutomationPeer 파생 클래스를 돌려 이름, 종류, 패턴을 노출합니다. 기존 컨트롤을 상속하는 중이면 대응하는 Peer(ButtonBase에는 ButtonBaseAutomationPeer)를 상속하면 이미 구현된 동작을 이어받을 수 있습니다.15
flowchart TB
accTitle: AutomationPeer로 정보를 노출하는 방식
accDescr: 사용자 지정 컨트롤은 OnCreateAutomationPeer를 오버라이드하고 AutomationPeer 파생 클래스를 돌려 이름, 종류, 패턴을 노출한다. 기존 컨트롤을 상속하는 중이면 대응하는 Peer를 상속해 이미 구현된 동작을 이어받는다
custom["사용자 지정 컨트롤"] --> ov["OnCreateAutomationPeer"]
ov --> peer["Peer 파생 클래스를 반환"]
peer --> pub["이름, 종류, 패턴을 노출"]
inherit["기존 컨트롤을 상속"] -.-> basepeer["대응하는 Peer를 상속"]
basepeer -.-> reuse["이미 구현된 동작을 이어받음"]
그림 10: 사용자 지정 컨트롤은 OnCreateAutomationPeer에서 Peer를 돌려 UIA에 정보를 노출한다.
// An example of a control that custom-draws line status as a coloured lamp
public class StatusLamp : Control
{
public static readonly DependencyProperty IsOnlineProperty =
DependencyProperty.Register(nameof(IsOnline), typeof(bool), typeof(StatusLamp),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender, OnIsOnlineChanged));
public bool IsOnline
{
get => (bool)GetValue(IsOnlineProperty);
set => SetValue(IsOnlineProperty, value);
}
internal static string NameFor(bool isOnline)
=> isOnline ? "Line status: online" : "Line status: offline";
private static void OnIsOnlineChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Raise a UIA property-changed event the moment the value changes. Without this,
// a screen reader keeps the old name and cannot notice the change of state
if (UIElementAutomationPeer.FromElement((UIElement)d) is AutomationPeer peer)
{
peer.RaisePropertyChangedEvent(
AutomationElementIdentifiers.NameProperty,
NameFor((bool)e.OldValue), NameFor((bool)e.NewValue));
}
}
protected override AutomationPeer OnCreateAutomationPeer()
=> new StatusLampAutomationPeer(this);
}
public class StatusLampAutomationPeer : FrameworkElementAutomationPeer
{
public StatusLampAutomationPeer(StatusLamp owner) : base(owner) { }
protected override AutomationControlType GetAutomationControlTypeCore()
=> AutomationControlType.Text; // Text-equivalent if it is a status display with no operation
protected override string GetNameCore()
=> StatusLamp.NameFor(((StatusLamp)Owner).IsOnline);
}
이름을 돌려주는 것만으로는 부족하고, 바뀌는 순간에 이벤트로 알리는 것도 Peer의 일입니다. 보조 기술에는 값을 다시 가져오는 독자 타이밍이 없으므로, 변경 이벤트를 올리지 않는 구현은 「다시 물었을 때만 올바른」 상태이며, 스크린 리더 사용자에게 상태 변화가 전해지지 않습니다.
sequenceDiagram
accTitle: 상태 변화를 스크린 리더에 알리는 흐름
accDescr: 컨트롤의 값이 바뀌는 순간 AutomationPeer가 Name 속성 변경 이벤트를 올리고, 보조 기술은 스스로 다시 가져오지 않으므로 이벤트가 없으면 옛 이름에 머물러 변화를 알아차리지 못한다
participant c as 컨트롤
participant p as AutomationPeer
participant s as 스크린 리더
c->>p: IsOnline 값이 바뀜
p->>s: Name 속성 변경 이벤트를 올림
s->>s: 새 상태를 알림
Note over s: 이벤트가 없으면 옛 이름에 머문다
그림 11: 값의 변화는 AutomationPeer가 변경 이벤트로 알릴 때만 스크린 리더에 도달한다.
사용자 지정 컨트롤에 조작이 있으면(누를 수 있고, 값을 바꿀 수 있고, 선택할 수 있으면) GetPattern을 오버라이드하고 IInvokeProvider나 IRangeValueProvider 같은 패턴 인터페이스를 제공합니다.15 핵심은 공유 컨트롤 라이브러리 쪽에 Peer도 만들면, 그것을 쓰는 모든 화면이 자동으로 대응된다는 점입니다. 그것이 9장의 「옆으로 펼치기」의 기반입니다.
6. 모든 기능에 키보드만으로 도달할 수 있는가?
WCAG 성공 기준 2.1.1(Keyboard)은 콘텐츠의 모든 기능이 키보드 인터페이스로 조작 가능해야 한다고 요구합니다.8 스크린 리더 사용자는 원칙적으로 마우스를 쓰지 않으므로, 키보드로 도달할 수 없는 기능은 없는 기능과 같습니다. 점검 관점은 다음과 같습니다.
| 관점 | 확인할 것 | WinForms / WPF의 주된 수단 |
|---|---|---|
| 탭 순서 | Tab 키 이동 순서가 시각 순서(왼쪽 위 → 오른쪽 아래)와 맞는가? | TabIndex 정리, TabStop 설정 |
| 액세스 키 | Alt+글자로 주요 항목에 바로 이동할 수 있는가? | WinForms는 Text의 &, WPF는 머리글의 _ |
| 바로 가기 | 자주 쓰는 조작(저장, 검색, 확정)에 단독 키가 있는가? | Ctrl+S 등을 할당하고 메뉴에 표시 |
| 포커스 표시 | 지금 포커스가 어디인지 눈으로 따라갈 수 있는가? | 포커스 사각형을 없애지 말고, 사용자 지정 그리기 때는 직접 그림 |
| 마우스 전용 기능 | 더블클릭, 오른쪽 클릭, 끌기, 가리키기로만 쓸 수 있는 기능이 있는가? | 같은 기능을 메뉴나 키에서도 제공 |
| 대화상자 | Enter = 기본 단추, Esc = 취소가 동작하는가? | AcceptButton/CancelButton, IsDefault/IsCancel |
WinForms 접근성 연습도 입력란의 바로 앞 탭 순서에 레이블을 두고, 사용자가 이동하고 싶은 컨트롤과 메뉴에 액세스 키를 다는 것을 기본으로 꼽습니다.12
강조하고 싶은 것은 이것이 「장애 지원을 위한 추가 비용」이 아니라는 점입니다. 수주 입력 같은 반복 업무에서, 손을 홈 포지션에서 떼지 않고 입력을 끝낼 수 있는지가 조작자의 처리량을 그대로 가릅니다. 흐트러진 탭 순서나 마우스가 필요한 조작은 모든 사용자의 생산성을 매일 조금씩 깎는 결함입니다. 접근성 대응과 키보드 효율은 같은 작업의 다른 이름일 뿐입니다(사용 환경별 우선순위는 「Windows 앱에서의 UX 설계의 사고방식」도 보십시오).
flowchart TB
accTitle: 키보드를 정리하는 이중 효과
accDescr: 탭 순서, 액세스 키, 포커스 표시를 갖추면 보조 기술 사용자가 기능에 도달할 수 있는 것과 모든 조작자의 입력 속도라는 두 효과가 한꺼번에 나오고, 마우스로만 쓸 수 있는 기능은 없는 것과 같다
seibi["키보드를 정리"] --> a11y["보조 기술 사용자"]
seibi --> speed["모든 조작자의 속도"]
mouse["마우스 전용 기능"] -.-> none["없는 것과 같다"]
그림 12: 키보드 조작을 정리하면 보조 기술 지원과 모든 사용자의 효율이 동시에 실현되며, 마우스 전용 기능은 없는 것과 같다.
7. 색과 대비 ── 4.5:1과 「색만이 수단이 아니다」
7.1. 대비비의 가이드는 4.5:1
WCAG 성공 기준 1.4.3(Contrast (Minimum))은 텍스트와 텍스트 이미지에 최소 4.5:1의 대비비, 큰 텍스트에는 최소 3:1을 요구합니다.8 흰 배경에 연회색 텍스트를 두는 현대적 디자인은 이 기준에 미달하는 경우가 드물지 않습니다. 업무 앱 사용자에는 나이와 함께 시력·색각이 바뀐 사람과, 공장처럼 어두운 환경에서 쓰는 사람이 포함됩니다. 설계 리뷰에서 대비 체커로 재는 습관을 들이십시오.
7.2. 색만으로 정보를 전하지 말 것
성공 기준 1.4.1(Use of Color)은 색이 정보를 전하는 유일한 시각 수단이어서는 안 된다는 것입니다.8 업무 앱의 전형 예는 다음과 같습니다.
- 오류 행을 빨간 글씨만으로 표시 → 오류 아이콘과 메시지 열도 제공
- 필수 항목을 레이블 색만으로 표시 → 「*」나 「필수」 문구를 더함
- 상태를 램프 색만으로 표시 → 색 + 도형, 또는 문구(「가동」, 「정지」)
색각의 다양성을 생각하면, 이것 역시 「특별 대응」이 아니라 표시 설계의 기본입니다.
flowchart TB
accTitle: 색만으로 전하던 정보를 바꾸기
accDescr: 오류를 빨간 글씨만으로 표시하던 것을 오류 아이콘과 메시지 열로 바꾸고, 필수를 레이블 색만으로 표시하던 것을 필수라는 문구를 더하는 것으로 바꾸며, 상태를 램프 색만으로 표시하던 것을 도형이나 문구와 조합하는 것으로 바꾼다
err["빨간 글씨만의 오류"] --> erra["아이콘과 문구도 제공"]
req["레이블 색만의 필수"] --> reqa["필수라는 문구를 더함"]
lamp["램프 색만의 상태"] --> lampa["색을 도형이나 문구와 조합"]
그림 13: 색만으로 전하던 전형 예는 아이콘, 문구, 도형이나 텍스트와 조합하는 것으로 바꾼다.
7.3. 대비 테마(고대비)를 따르기
Windows에는 전경·배경의 분리가 강한 색 구성으로 바꾸는 대비 테마(이전의 고대비)가 있으며, 사용자는 대비비가 대체로 7:1 이상이 되도록 설계된 내장 테마를 고르고 편집할 수 있습니다.9 앱 측의 원칙은 단순합니다. 색을 하드코딩하지 말고 시스템 색을 존중하십시오.
- WinForms: ForeColor/BackColor를 기본값으로 두면 사용자의 색 설정이 쓰입니다. 자기 색을 적용한 곳은 SystemInformation.HighContrast로 판단하고 SystemColors 기반 구성으로 바꾸며, UserPreferenceChanged 이벤트로 설정 변경을 따릅니다.12
- WPF/WinUI: SystemColors 클래스 리소스를 참조하면 테마 전환을 따릅니다. 자기 브러시로 채운 곳이 깨짐의 원인이 됩니다.9
flowchart TB
accTitle: 대비 테마를 따르기
accDescr: 색을 하드코딩한 곳은 대비 테마로 바꾸면 깨지므로 SystemColors 기반 구성으로 바꾸고 설정 변경 이벤트로 따른다. 시스템 색을 참조하면 사용자 색을 자동으로 따를 수 있다
theme["대비 테마로 전환"] --> qh{"색은 어떻게 지정되어 있는가?"}
qh -->|하드코딩| broken["색 구성이 깨진다"]
qh -->|시스템 색 참조| ok["사용자 색을 자동으로 따름"]
broken -.-> fix["SystemColors로 전환"]
fix -.-> ev["설정 변경 이벤트로 따름"]
그림 14: 대비 테마에서 깨지는 것은 색을 하드코딩한 곳뿐이며, 시스템 색 참조는 자동으로 따른다.
또한 저시력 사용자는 높은 OS 배율(DPI 스케일링)을 자주 쓰므로, 고DPI 대응도 접근성 대응의 일부입니다. 125%–200%에서 레이아웃이 깨지는 앱은 그 시점에서 쓸 수 없습니다. 자세한 내용은 「WinForms의 고DPI 대응」과 「WPF의 고DPI 대응」을 보십시오.
8. 검증 실무 ── Accessibility Insights와 스크린 리더 실습
8.1. Accessibility Insights for Windows
Microsoft는 Windows 앱의 접근성 검증 도구로 Accessibility Insights for Windows를 제공하며, 주된 쓰임은 셋입니다.10
- Live Inspect: 요소 위에 마우스를 올리거나 키보드로 포커스하기만 하면 UIA 속성(Name, ControlType, 패턴 등)을 확인할 수 있습니다. 「이 단추의 Name이 무엇인가」를 보는 가장 짧은 수단입니다.
- FastPass: 5분 안에 영향이 큰 접근성 문제를 검출하는 가벼운 점검입니다. Name 누락처럼 기계적으로 판단할 수 있는 문제를 신규 화면마다 목록화할 수 있습니다.
- Troubleshooting: 특정 문제의 진단과 수정을 돕습니다. 검출된 문제에서 이 글이 인용하는 프레임워크별 수정 가이드로 바로 걸어갈 수 있습니다.
Windows SDK에 포함된 Inspect.exe와 AccEvent도 UIA 트리와 속성을 확인할 수 있지만, 레거시 도구로 위치하며 지금은 Accessibility Insights로의 이전이 권장됩니다.10
flowchart TB
accTitle: Accessibility Insights의 세 가지 쓰임
accDescr: Accessibility Insights for Windows는 Live Inspect로 UIA 속성을 확인하고, FastPass로 영향이 큰 문제를 가볍게 점검하며, Troubleshooting으로 문제의 진단과 수정을 돕는다. Inspect.exe 같은 레거시 도구에서의 이전이 권장된다
ai["Accessibility Insights"] --> live["Live Inspect"]
ai --> fast["FastPass"]
ai --> ts["Troubleshooting"]
live --> livef["UIA 속성을 확인"]
fast --> fastf["영향이 큰 문제를 검출"]
ts --> tsf["진단과 수정을 도움"]
legacy["Inspect.exe 등"] -.->|이전이 권장됨| ai
그림 15: Accessibility Insights에는 확인, 검출, 진단의 세 쓰임이 있으며, 레거시 도구의 이전 목적지이다.
8.2. 스크린 리더로 실습하기
도구의 자동 점검이 검출할 수 있는 것은 기계적으로 판단할 수 있는 문제뿐입니다. 마지막에는 반드시 스크린 리더로 실제 업무 조작을 걸어 보십시오. Windows 내장 내레이터는 Ctrl+Windows 키+Enter로 바로 시작할 수 있고, NVDA는 무료로 도입할 수 있습니다.11 점검의 요령은 화면을 보지 않고(또는 디스플레이를 끄고) 알림만 의지해 「주문을 하나 입력하고 확정한다」같은 실제 작업을 끝낼 수 있는지 시험하는 것입니다. 이름은 있지만 알림 순서가 뒤섞이거나, 포커스가 모달 밖으로 빠지는 문제는 실습에서만 발견됩니다.
flowchart TB
accTitle: 도구 검증과 실습의 조합
accDescr: FastPass 같은 자동 점검이 검출할 수 있는 것은 기계적으로 판단할 수 있는 문제뿐이며, 나머지는 스크린 리더로 실제 업무 조작을 걸어 알림 순서와 포커스 문제를 찾는 실습으로 발견한다
tool["도구의 자동 점검"] --> kikai["기계적으로 판단할 수 있는 문제"]
tool -.-> nokori["검출하지 못하는 문제가 남음"]
nokori --> sr["스크린 리더 실습"]
sr --> task["업무 조작을 걸음"]
task --> mieru["알림 순서와 포커스 문제"]
그림 16: 자동 점검으로 기계적 문제를 목록화하고, 나머지는 스크린 리더 실습으로 찾는다.
8.3. 개발 흐름에 넣고, UI 자동 테스트와 서로 이득을 보기
검증이 사람 의존이 되지 않게 하려면, 다음 체크리스트를 신규 화면의 리뷰 항목에 넣기를 권합니다.
| # | 점검 항목 | 수단 |
|---|---|---|
| 1 | FastPass 오류 0건 | Accessibility Insights |
| 2 | 모든 입력란과 단추에 Name이 있음 | Live Inspect |
| 3 | Tab 키만으로 모든 기능에 도달 | 수동 |
| 4 | Enter/Esc와 주요 바로 가기가 동작 | 수동 |
| 5 | 텍스트 대비비 4.5:1 이상 | 대비 체커 |
| 6 | 대비 테마에서 깨지지 않음 | 테마를 바꿔 눈으로 점검 |
| 7 | 200% 배율에서 깨지지 않음 | 표시 설정을 바꿔 눈으로 점검 |
| 8 | 스크린 리더로 대표 작업을 끝낼 수 있음 | 내레이터/NVDA |
그리고 하나 더. FlaUI 같은 UI 자동 테스트는 스크린 리더가 쓰는 것과 같은 UIA 위에 만들어져 있습니다. 접근성을 위해 갖춘 Name과 패턴이 테스트 코드의 부품이 되고, 테스트용으로 설계한 AutomationId는 Live Inspect 디버깅을 쉽게 합니다. 반대로 UIA 트리에 나타나지 않는 UI는 테스트에도 보조 기술에도 보이지 않습니다. 접근성과 테스트 가능성은 같은 투자의 양면입니다(「Windows 데스크톱 앱의 UI 자동 테스트」).
flowchart TB
accTitle: 접근성과 UI 자동 테스트의 서로 이득
accDescr: 스크린 리더와 FlaUI 같은 UI 자동 테스트는 같은 UIA 위에 만들어져 있으므로, 갖춘 Name과 패턴을 양쪽에서 쓸 수 있고, UIA 트리에 나타나지 않는 UI는 어느 쪽에서도 보이지 않는다
uia["UIA 트리를 정리"] --> sr["스크린 리더가 읽을 수 있음"]
uia --> test["UI 자동 테스트에서 쓸 수 있음"]
sr -.-> both["같은 투자의 양면"]
test -.-> both
hidden["UIA에 나타나지 않는 UI"] -.-> invisible["어느 쪽에서도 보이지 않음"]
그림 17: 같은 UIA 기반 위에 있으므로, UIA 트리를 정리하면 보조 기술과 UI 자동 테스트 모두에 이득이 된다.
9. 우선순위를 정하는 법 ── 모든 화면을 한꺼번에 고치지 말 것
수백 화면의 핵심 시스템을 한꺼번에 고치는 것은 비용과 품질 모두에서 비현실적입니다. 권하는 접근은 다음 세 층입니다.
- 그 사용자가 업무에서 쓰는 화면부터 고칩니다. 합리적 배려는 당사자의 요청에 개별적으로 대응하는 과정입니다.1 먼저 당사자가 실제 업무를 스크린 리더로 조작하게 하고, 어디서 막히는지 함께 특정합니다. 많은 경우 일상 업무에서 쓰는 화면은 몇 개에서 열몇 개로 좁혀지고, 그중 치명적인 문제(이름 없는 단추, 키보드로 누를 수 없는 확정 단추)는 며칠의 수정으로 해소할 수 있습니다.
- 신규 개발은 기준에 맞춥니다. 8장의 체크리스트를 Definition of Done에 더하고, 신규 화면은 처음부터 대응된 상태로 만듭니다. 사후 수정과 달리, 설계 때 넣는 비용 증가는 작습니다.
- 공유 컨트롤을 고쳐 옆으로 펼칩니다. 검색 대화상자, 그리드, 날짜 입력 같은 사내 공유 부품에 기본 AccessibleName이나 AutomationPeer를 구현하면, 그것을 쓰는 모든 화면에 한꺼번에 효과가 납니다. 개별 화면을 하나씩 만지는 것보다 훨씬 비용 대비가 좋은 수입니다.
flowchart TB
accTitle: 수정 우선순위의 세 층
accDescr: 사용자가 업무에서 쓰는 화면부터 고치고, 신규 개발은 체크리스트로 기준에 맞추며, 공유 컨트롤을 고쳐 모든 화면으로 펼친다
s1["1. 사용자가 쓰는 화면부터 고침"] --> s2["2. 신규는 기준에 맞춤"] --> s3["3. 공유 컨트롤로 옆으로 펼침"]
s3 -.-> all["쓰는 모든 화면에 한꺼번에 효과"]
그림 18: 모든 화면을 한꺼번에 고치지 말고, 사용 중 화면, 신규, 공유 부품의 세 층으로 나아간다.
그리고 대화의 기록은 기술 대응만큼 중요합니다. 합리적 배려는 「모든 요청을 완전히 충족하는」 과정이 아니라 「개별적으로 대화하고 조정하는」 과정입니다. 당사자와 대체 수단을 생각하고(그 업무를 다른 화면에서 하기, CSV보내기를 준비하기, 운용으로 커버하기), 부담이 너무 큰 수정에는 합의하는 것도 건설적 대화의 정당한 결과입니다.1 무엇이 요청되었고, 무엇에 대응했으며, 무엇을 대체 수단으로 했는지를 기록하는 것이 조직의 성실한 증명이 됩니다.
flowchart TB
accTitle: 건설적 대화와 기록의 흐름
accDescr: 장애인의 요청에 건설적 대화로 대응하고, 대응할 수 있는 수정은 실행하며, 부담이 너무 큰 수정은 당사자와 대체 수단을 생각하고 합의하고, 무엇이 요청되었고 무엇에 대응했으며 무엇을 대체 수단으로 했는지를 기록한다
req["요청"] --> talk["건설적 대화"]
talk --> q{"부담이 너무 큰가?"}
q -->|아니오| kaishu["수정으로 대응"]
q -->|예| alt["대체 수단을 생각하고 합의"]
kaishu --> rec["이력을 기록"]
alt --> rec
그림 19: 건설적 대화에서는 수정 또는 대체 수단을 당사자와 합의하고, 그 이력을 기록에 남긴다.
10. 정리
- 2024년 4월 시행된 개정 장애인차별해소법으로 합리적 배려의 제공이 사업자에게도 의무가 되었습니다. 고용 분야는 2016년부터 장애인고용촉진법 아래 고용주 의무입니다. 앱을 미리 쓰기 쉽게 만드는 것은 「환경 정비」(노력 의무)이며, 더 나아갈수록 개별 대응은 가벼워집니다.
- 기술 기준은 WCAG(JIS X 8341-3:2016)에 모여 있고, WCAG2ICT를 통해 데스크톱 앱에도 같은 생각을 적용할 수 있습니다.
- 스크린 리더는 UI Automation을 통해 앱을 읽습니다. UIA 트리, 속성(Name/ControlType/AutomationId), 컨트롤 패턴의 삼위일체가 기반입니다.
- 최우선은 Name입니다. WinForms는 AccessibleName과 탭 순서로 Label을 연결하고, WPF는 AutomationProperties.Name/LabeledBy, 사용자 지정 컨트롤은 AutomationPeer를 씁니다.
- 모든 기능에 키보드만으로 도달할 수 있는 것은 WCAG 성공 기준이며, 동시에 모든 조작자의 생산성입니다. 탭 순서, 액세스 키, 포커스 표시를 정리하십시오.
- 색의 세 기본은 대비비 4.5:1, 색만이 수단이 아님, 대비 테마에서 시스템 색을 존중하는 것입니다.
- 검증은 Accessibility Insights의 FastPass+Live Inspect와 내레이터/NVDA 실습을 조합하고, 신규 화면 체크리스트로 개발 흐름에 넣습니다.
- 모든 화면을 한꺼번에 고치지 말고, 사용자가 쓰는 화면 → 신규의 기준 대응 → 공유 컨트롤의 옆으로 펼치기 순으로 나아갑니다. 합리적 배려는 대화의 과정이며, 이력의 기록이 조직을 지킵니다.
첫 단계로 주요 화면 하나를 골라 Accessibility Insights for Windows의 FastPass를 돌린 뒤, Tab 키만으로 업무를 걸어 보기를 권합니다. 30분이면 자기 앱의 현재 위치가 놀랄 만큼 구체가 됩니다.
관련 기사
- Windows 데스크톱 앱의 UI 자동 테스트 ── UI Automation의 원리와 FlaUI로 만드는 잘 깨지지 않는 테스트
- Windows 앱에서의 UX 설계의 사고방식 - ToC / ToB / 감시 / 현장 단말 / 상주 도구에서 무엇을 우선할지의 판단표
- WinForms의 고DPI 대응 - 4K 모니터에서 흐려지거나 깨지는 원인과 현실적인 대처법
- WPF의 고DPI 대응 ── 「DPI에 강할 텐데」인데도 흐릿하고・번지는 원인과 대처
- 코무라소프트가 디지털청 디자인 시스템으로 홈페이지를 만드는 이유 ── 저가와 품질은 양립할 수 있다
- 일본어 글꼴과 문자의 함정 ── 업무 앱에서 JIS2004, IVS, 외자를 다루기
관련 상담 영역
합동회사 코무라소프트에서는 WinForms/WPF 업무 앱의 접근성 수정(스크린 리더 대응, 키보드 조작 정리, 대비 테마 대응), 공유 컨트롤에 AutomationPeer를 구현하는 작업, Accessibility Insights로 현재 상태를 진단하고 우선순위를 정하는 상담을 다룹니다. 「직원이 우리 앱을 스크린 리더로 쓸 수 있는지 확인하고 싶다」는 단계에서 시작해도 됩니다.
참고 링크
-
Cabinet Office, Leaflet “From 1 April 2024, the provision of reasonable accommodation became an obligation”. 레이와 3년 개정 장애인차별해소법이 레이와 6년 4월 1일 시행되어 사업자의 합리적 배려 제공이 의무가 되었다는 점, 합리적 배려의 제공이 장애인의 의사 표시에 과중한 부담이 되지 않는 범위에서 대응하는 것이라는 점, 건설적 대화의 중요성과 일방적 거부가 의무 위반이 될 수 있다는 점, 불특정 다수의 장애인을 향한 사전 개선 조치인 「환경 정비」가 노력 의무라는 점, 고용과 근무가 장애인고용촉진법의 규정을 따른다는 점에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10
-
Ministry of Health, Labour and Welfare, The prohibition of discrimination against persons with disabilities in employment and the obligation to provide reasonable accommodation. 헤이세이 28년 4월 시행된 개정 장애인고용촉진법이 고용주에게 고용에서의 장애 차별 금지와 과중한 부담이 되지 않는 범위의 합리적 배려 제공을 의무로 두었다는 점, 합리적 배려 지침 등 관련 자료에 대해. ↩ ↩2 ↩3 ↩4
-
Web Accessibility Infrastructure Committee (WAIC), Understanding JIS X 8341-3:2016. JIS X 8341-3:2016이 ISO/IEC 40500:2012의 대응 규격이며 규격 본문이 WCAG 2.0과 같은 내용이라는 점, 규격이 가정하는 웹 콘텐츠의 범위에 대해. ↩ ↩2
-
W3C, Guidance on Applying WCAG 2 to Non-Web Information and Communications Technologies (WCAG2ICT). WCAG 2.0/2.1/2.2의 원칙, 가이드라인, 성공 기준을 비웹 문서와 소프트웨어에 적용하는 법을 보여 주는 W3C Group Note에 대해. ↩ ↩2
-
Microsoft Learn, UI Automation Specification. UI Automation이 스크린 리더 같은 보조 기술에 UI 정보를 제공하고 표준 입력 이외의 수단으로 조작을 가능하게 한다는 점, UIA 요소, 트리, 속성, 컨트롤 패턴, 컨트롤 종류, 이벤트의 구성에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, WinForms: Setting the accessible name on a control. 일부 컨트롤에서 Text가 UIA Name으로 재사용되는 반면 ComboBox, ListBox, ListView, PictureBox, ProgressBar, TabControl, TextBox, TreeView 등은 재사용하지 않는다는 점, 대상 컨트롤을 Label의 TabIndex 바로 다음에 두면 Label의 텍스트가 Name으로 쓰인다는 점, AccessibleName을 명시적으로 설정하는 것과 디자이너 파일에 빈 문자열이 남는 문제에 대해. ↩ ↩2 ↩3 ↩4
-
W3C / Web Accessibility Infrastructure Committee (WAIC) translation, Web Content Accessibility Guidelines (WCAG) 2.1 Japanese translation. 성공 기준 1.4.3(Contrast (Minimum))의 텍스트 4.5:1과 큰 텍스트 3:1, 성공 기준 1.4.1(Use of Color)의 색만이 시각 수단이 아니어야 한다는 점, 성공 기준 2.1.1(Keyboard)의 모든 기능의 키보드 조작성에 대해. ↩ ↩2 ↩3 ↩4 ↩5 ↩6
-
Microsoft Learn, Contrast themes. 대비 테마가 대체로 7:1 이상의 대비비의 제약된 팔레트를 쓴다는 점, 내장 테마를 고르고 색을 편집하는 점, SystemColor 클래스 리소스가 전경/배경 쌍으로 정의되어 테마 전환을 자동으로 따른다는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Accessibility testing. Accessibility Insights for Windows의 세 시나리오── Live Inspect(가리키기/포커스로 UIA 속성 확인), FastPass(5분 안에 영향이 큰 문제 검출), Troubleshooting──과 Inspect, AccEvent 같은 레거시 도구에서의 이전 권장에 대해. ↩ ↩2 ↩3
-
NVDA Japanese Team, NVDA Japanese edition. 무료 오픈 소스 Windows 스크린 리더 NVDA와 일본어판 제공에 대해. ↩ ↩2
-
Microsoft Learn, Walkthrough: Creating an Accessible Windows-based Application. 입력란의 바로 앞 탭 순서에 설명 Label을 두는 점, Text의 &로 액세스 키를 다는 점, SystemInformation.HighContrast로 고대비를 판단하고 SystemColors를 쓰는 점, UserPreferenceChanged 이벤트를 따르는 점, 색으로 전하는 정보에 시각 단서를 조합하는 점에 대해. ↩ ↩2 ↩3
-
Microsoft Learn, Providing Accessibility Information for Controls. WinForms 컨트롤의 AccessibleName, AccessibleDescription, AccessibleRole, AccessibleDefaultActionDescription 속성과 설정 방법에 대해. ↩
-
Microsoft Learn, WPF: Setting the accessible name on an edit field. TextBlock의 Text는 UIA Name으로 재사용되는 반면 TextBox의 Text는 UIA Value로 노출된다는 점, 레이블 TextBlock을 AutomationProperties.LabeledBy로 TextBox에 연결하거나 AutomationProperties.Name을 설정하는 점에 대해. ↩
-
Microsoft Learn, UI Automation of a WPF Custom Control. 사용자 지정 컨트롤이 OnCreateAutomationPeer를 오버라이드하고 AutomationPeer 파생 클래스를 돌려주는 점, 기반 컨트롤에 대응하는 Peer 클래스를 상속하는 점, GetPattern으로 패턴 프로바이더를 제공하는 점, XAML 측에서 AutomationProperties 특성으로 오버라이드하는 점에 대해. ↩ ↩2
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
Windows 데스크톱 앱의 UI 자동 테스트 ── UI Automation의 원리와 FlaUI로 만드는 잘 깨지지 않는 테스트
WinForms/WPF 앱의 UI 자동 테스트를 Windows UI Automation의 원리(트리·AutomationId·컨트롤 패턴)부터 정리합니다. FlaUI를 이용한 최소 구현, WinAppDriver의 현재 상황, AutomationId...
Windows 앱 외주·수탁 개발을 의뢰하기 전에 정리해야 할 것
Windows 앱의 외주·수탁 개발을 의뢰하기 전에, 기존 소프트웨어 개수, 장치 연계, COM/ActiveX, 배포·업데이트, 보수와 관련해 정리해야 할 포인트를 설명합니다.
「응답 없음」의 정체 ── Windows가 앱의 행을 판단하는 방식과 멈추지 않는 설계
Windows의 「응답 없음」은 창이 5초 동안 메시지를 꺼내지 않았다고 OS가 판단해 고스트 창으로 바꾸는 메커니즘입니다. 그 판단의 내부, 행의 고전적 원인, 무거운 작업을 UI 스레드에서 떼어 내는 설계, 행 조사 절차를 정리합니다.
클립보드와 드래그 앤 드롭의 구조 ── 업무 앱에서 OLE 데이터 전송을 올바르게 다루기
Excel 표를 붙여 넣으면 서식이 무너지고, 원본 앱을 닫으면 붙여 넣을 수 없게 되는 일── 둘 다 클립보드가 같은 내용을 여러 형식으로 한꺼번에 두기 때문입니다. 표준 형식, 지연 렌더링, OLE 드래그 앤 드롭, 클립보드 기록과 클라우드 ...
WinForms/WPF 앱에 Entra ID 인증 넣기 ── MSAL.NET과 WAM 브로커 실무 구성
WinForms/WPF 데스크톱 앱에 Entra ID(구 Azure AD) 인증을 도입하는 절차를 실무 관점에서 정리합니다. 퍼블릭 클라이언트의 개념, ROPC 폐지 현황, 앱 등록, MSAL.NET의 AcquireTokenSilent 패턴, W...
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
UI 스레드 & 타이머
WPF / WinForms UI 스레드, async 흐름, Dispatcher 사용, 타이머 판단을 정리한 토픽 페이지입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- 업무 앱의 접근성 대응은 법으로 의무인가요?
- 2021년 개정 장애인차별해소법이 2024년 4월 1일 시행되어, 장애인에 대한 합리적 배려의 제공이 사업자에게도 의무가 되었습니다. 합리적 배려는 장애인이 요청했을 때 과중한 부담이 되지 않는 범위에서 개별 장벽을 제거하는 대응이며, 앱을 미리 쓰기 쉽게 만드는 것은 「환경 정비」라는 노력 의무로 위치합니다. 직원과 회사의 관계 같은 고용은 그 법이 아니라 장애인고용촉진법의 영역이며, 2016년 4월 시행 개정부터 고용주에게 합리적 배려를 의무로 두고 있습니다. 즉 「직원이 업무 앱을 쓸 수 없다」는 상황은 이미 오래전부터 의무의 영역입니다. 개별 사안에서 어디까지 갈지는 개별 상황에 따르므로, 내각부와 후생노동성의 1차 정보를 확인하고 당사자와의 대화를 통해 결정합니다.
- 스크린 리더는 Windows 데스크톱 앱을 어떻게 읽나요?
- 내레이터와 NVDA 같은 스크린 리더는 UI Automation(UIA)이라는 접근성 기반을 통해 앱의 UI를 읽습니다. 앱 측은 화면 요소를 UIA 트리라는 구조로 노출하고, 각 요소는 Name(목적)과 ControlType(종류) 같은 속성, Invoke(누르기)와 Value(값) 같은 컨트롤 패턴을 가집니다. 스크린 리더는 이 정보를 「주문 확정 단추」로 알리고 패턴을 통해 조작합니다. 표준 WinForms와 WPF 컨트롤은 처음부터 이 메커니즘을 가지므로, 개발자의 주된 일은 Name을 비워 두지 않고, UI를 키보드로 조작할 수 있게 하며, 사용자 지정 컨트롤에 정보를 구현하는 것입니다.
- 기존 WinForms 앱에서는 무엇부터 시작해야 하나요?
- 가장 짧은 길은 Accessibility Insights for Windows의 FastPass를 대상 화면에 돌려 Name이 비어 있는 컨트롤과 탭 순서 문제를 목록화하는 것입니다. 수정은 아이콘만 있는 단추에 AccessibleName을 설정하고, 입력란의 바로 앞 탭 순서에 Label을 연결하며, TabIndex를 시각 순서와 맞게 정리하는 데서 시작합니다. 이어서 내레이터나 NVDA를 켜고 화면을 보지 않은 채 실제 업무 조작을 걸어, 어디서 막히는지 확인합니다. 모든 화면을 한꺼번에 고칠 필요는 없고, 실제로 쓰는 화면부터 시작하며 신규 화면은 체크리스트로 기준을 맞추는 것이 현실적입니다.
- 고대비(대비 테마) 대응은 어떻게 해야 하나요?
- 기준은 색을 하드코딩하지 않고 시스템 색을 존중하는 것입니다. WinForms에서는 ForeColor/BackColor를 기본값으로 두거나 SystemColors를 쓰고, SystemInformation.HighContrast로 상태를 판단하며, UserPreferenceChanged 이벤트로 전환을 따릅니다. WPF와 WinUI에서도 SystemColors 클래스 리소스를 참조하면 테마 전환을 자동으로 따릅니다. 동시에 오류를 빨간색만으로 알리는 것처럼 「색만으로」 정보를 전하지 말고, 아이콘이나 문구와 조합합니다. 보통 테마에서도 텍스트 대비비 4.5:1 이상이라는 WCAG 기준을 가이드로 삼으면, 어두운 현장과 고령 사용자에게도 UI가 더 읽히게 됩니다.
- 접근성 대응이 UI 자동 테스트에도 도움이 되나요?
- 됩니다. FlaUI 같은 UI 자동 테스트 도구는 스크린 리더가 쓰는 것과 같은 UI Automation 위에 만들어져 있습니다. 접근성을 위해 갖춘 Name, ControlType, 컨트롤 패턴을 테스트 코드에서 그대로 쓸 수 있고, 테스트용으로 설계한 AutomationId는 요소 식별을 안정시킵니다. 반대로 UIA 트리에 나타나지 않는 사용자 지정 그리기 UI는 스크린 리더에도 테스트에도 보이지 않습니다. 접근성과 자동 테스트는 같은 기반에 대한 투자이므로, 어느 한쪽을 갖추면 다른 쪽의 비용도 내려갑니다.