블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2853)
Unity3D (895)
Programming (479)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (189)
협업 (64)
3DS Max (3)
Game (12)
Utility (142)
Etc (99)
Link (34)
Portfolio (19)
Subject (90)
iOS,OSX (53)
Android (16)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (19)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

치킨 명소

Etc / 2010. 9. 9. 14:26


반응형
Posted by blueasa
, |




내용추가 (2010.9.4)
[3]-6번은 미국에만 해당되고 국내는 해당 안된다고 합니다. 
원글 내용 수정했습니다. 

아이폰4를 받고 최초로 동기화하기 전에 반드시 확인해야 할 것들, 
동기화하는 동안에 체크할 것들, 동기화하고 나서 체크할 것들을 
일목요연하게 정리해 놓은 글이 있어서 옯겨봤습니다. 

몇가지를 제외하고는 아이폰 3GS 사용자라면 이미 아는 팁들일 수도 있겠지만 
막상 아이폰4를 받으면 체크 리스트를 만들지 않는 한  
빠짐없이 확인하기가 힘들 것 같아서 미리 정리해 봤어요. 

이 팁은 TUAW에서 가져왔어요. 
대략의 내용만 옮겼으니 좀 더 자세히 보고 싶으신 분은 원문 링크 
를 참조하시구요.  



[1] 아이튠스 동기화 전에 체크할 것들

1. 표면 유리와 연결 부위.
유리에 스크래치는 없는지, 갈라진 틈은 없는지, 
느슨하게 연결된 부위는 없는지, 
앞/뒷면 유리와 스테인레스 부분이 평행을 이루는지 확인.  
틈새가 있으면 내부에 먼지가 유입되는 것은 물론, 
실수로 떨어뜨리는 경우 치명적인 손상을 가져올 수 있습니다.  
틈새가 벌어진 부분은 육안으로 식별하기가 힘들기 때문에 
아주 밝은 불빛 아래서 확대경으로 구석구석 살피는 것이 좋습니다. 


2. 홈버튼/슬립버튼
아이폰을 동기화하기 전 반드시 테스트해야 하는 것들 중 하나.  
너무 느슨하거나 너무 빡빡한지, 
힘을 줘서 눌려야 작동한다면 문제가 있는겁니다.

3. 진동 스위치
진동 스위치가 잘 밀어지는지, 진동이 즉각 적용되는지 확인합니다. 



[2] 아이튠스 동기화 하는 동안 체크할 것들

1. 케이블 접속 불량 여부
케이블을 PC에 연결했을 때 아이튠스에 아이폰이 뜨는지, 충전이 되는지 확인합니다. 
케이블 접속 불량인 경우 컴퓨터와 동기화되지 않거나 충전이 되지 않습니다. 


2. 플래시 메모리
아이폰의 플래시 메모리 칩이 오염된 경우 아이튠스 동기화시 에러가 뜰 수 있어요. 
먼지를 털어낸다던가 컴퓨터 USB 드라이브를 다른 곳에 꽂는 등 
여러가지 시도를 했음에도 불구하고 동기화가 안되다면 
아이폰 플래시 메모리에 문제점이 있는지 의심해 봐야 합니다.
메모리 불량 여부를 테스트하는 가장 간단한 방법은 
처음 동기화할 때 가능한 많은 동영상이나 음악을 넣어보는 것입니다. 
32GB 아이폰4라면 동기화하는데 보통 1-2시간 걸리는 것이 정상입니다.



[3] 동기화 하고 나서 체크할 것들

1. 볼륨 버튼 
볼륨 버튼이 제대로 작동하는지 확인해 봅니다. 


2. 이어폰 잭
아이폰에 딸려온 번들 이어폰을 꽂았을 때 흔들림이 없이 딱 맞는지 확인합니다.  
이어폰으로 음악을 들어보고, 잘 들리지 않는 경우 다른 이어폰으로 테스트해서 
이어폰 문제인지 이어폰 잭 접속부위 문제인지를 확인해 봅니다. 
플레이, 중지, 앞뒤 트랙 넘어가기, 볼륨 등 모든 기능을 확인해 봅니다. 


3. 카메라
사진 몇장을 찍어서 셔터가 잘 열리고 닫히는지 확인해 봅니다. 
아이폰의 "tap to focus" 기능을 테스트해 봅니다.  
거리와 조명의 차이를 두고. 배경을 밝게 하거나. 
화면에서 탭을 했을 때 포커스/밝기가 조절되는지 확인해 봅니다.   
사진찍을 때 스크린 왼쪽 윗부분을 탭해서 
LED 플래시가 작동하는지 테스트 해봅니다.  
동영상을 촬영해 보고, 촬영한 동영상을 플레이할 때 사운드가 들리는지 확인.
찍은 사진에 왜곡이나 문제점이 없는지 확인해 봅니다.  


4. 액셀로메터
아이폰을 가로/세로 로 놓았을 때 화면이 바뀌는지 확인. 
메모 어플로 키보드가 가로세로 모드로 잘 작동하는지 확인
입력 후 흔들면 입력을 취소하겠느냐고 묻는 창이 뜨는지 확인


5. 안테나
3G가 되는 곳에서 신호가 자동으로 잡히는지 확인합니다.   
사파리를 열어서 웹페이지 접속이 잘 되는지 확인해 봅니다. 
속도 차이는 있겠지만, 3G를 사용하는 경우 
페이지가 뜰때까지 몇분씩 기다려야 한다면 안테나를 의심해 봐야 합니다. 


6. EDGE/GPR (요 부분은 미국에만 해당된다고 해요. 국내 사용자는 패스~)
3G 신호가 잡히는 경우, 설정 - 일반 - 네트워크로 가서 
3G사용을 꺼주면 아이폰은 몇초만에 EDGE/GPRS 모드로 변환됩니다. 
사파리로 웹페이지에 접속해 보고 지나치게 속도가 느린지 확인해 봅니다. 
--> 

7. GPS
지도 어플을 열고 왼쪽 아래 화살표 버튼을 눌러서 
현재 위치가 파란색 원으로 표시되는지 확인해 봅니다. 
전파가 약한 지역에 있지 않는 한 현재 위치가 잡힐겁니다. 
아이폰 4의 GPS 안테나는 3GS보다 훨씬 정확하고 강력하기 때문에 
3G의 경우 실내에서 위치를 잡지 못하는 경우가 있지만 
아이폰4는 실내에서도 현재 위치를 잘 잡아줍니다. 
따라서 현재 위치가 잘 표시되어야 정상입니다. 
만일 못잡는다면 실외에서 테스트해 봅니다. 
실외에서도 못잡는다면 문제가 있는 것으로 봐야 합니다. 


8. 블루투스
설정 - 일반 - 네트워크 - 인터넷 테터링 On - 블루투스 활성화
주변의 블루투스 기기를 테스트해 봅니다. 


9. 와이파이
아이폰의 와이파이 옵션을 On 시켜놓은 상태에서 
아이폰이 주변의 모든 무선 네트워크 기기를 인식하는지 확인해 봅니다. 


10. 터치 스크린
아이폰 터치스크린에 데드 스팟이 없는지 확인.
노트 어플이나 사파리 등 텍스트 입력이 가능한 어플을 실행시키고 
"The quick brown fox jumps over the lazy dog" 을 
가로모드, 세로모드(홈 버튼이 왼쪽, 오른쪽으로 가게 놓고)로 입력해 봅니다. 
사진 어플을 실행시켜 사진을 열어 확대해보고, 화면 전체 보기 모드로 놓고 
화면을 손으로 밀어서 사진이 제대로 움직이는지 확인해 봅니다. 


11. LCD
플래시라이트 어플을 받아서 확인해 봅니다. 
백라이트는 설정 - 밝기 조절 - 슬라이더를 좌우로 움직여서 확인해 봅니다.


12. 라이트 센서
어두운 곳에서 설정 - 밝기 메뉴로 제대로 작동하는지 확인해 봅니다. 
밝기 자동 조절 옵션을 켠 상태에서 주변을 어둡게 헤서 밝기가 자동으로 조절되는지 확인해 봅니다.  


13. CPU/GPU
아이폰 4의 프로세서와 그래픽 하드웨어는 
3D 게임에서 뛰어난 성능을 발휘합니다. 
그래픽이 왜곡되거나 겹쳐 보이면 GPU에 문제점이 있는 것입니다. 
 지나치게 뜨거워지거나 버벅거리면 CPU 문제점을 의심해봐야 합니다. 
고화질 무비기 아이폰4에서 잘 보이는지도 확인해 봅니다.


14. 자기 탐지기 
나침반 어플을 실행시켜 우측 하단 버튼을 눌러서 
진북/좌북 변환이 가능한지 확인해 봅니다. 
8가지 위치로 변경해도 신호를 잡지 못하면 문제가 있는 것입니다. 


15. 자이로스코프
아이폰4에는  기본으로 제공되는 자이로스코프 어플이 없습니다. 
무료 어플 Gyroscope를 다운받아서 테스트해 봅니다. 
이 어플을 사용하면 아이폰4의 자이로스코프가 작동하는지 즉각 알 수 있습니다. 



16. 통화 테스트

1) 마이크로폰
스피커폰 모드와 정상 모드에서 통화 테스트를 해봅니다. 
전화를 걸어서 잘 들리는지 확인해 봅니다. 
아이폰4로 통화랄 때 들리지 않는다는 경우도 있었습니다. 
아이폰 4의 마이크로폰 문제점 때문인지, 
노이즈 제거 기능이 지나치게 민감해서 그런 것인지는
아직 확인되지 않은 것 같습니다. 

2) 스피커
이어폰 스피커와 아이폰 하단 스피커가 잘 들리는지, 사운드의 왜곡이 없는지 획인해 봅니다.

3) 근접 센서
아이폰 4 터치 스크린은 아이폰을 귀에 대면 꺼지고, 귀를 떼면 다시 켜져야 정상입니다. 
아이폰 4의 근접 센서가 통화하는 동안 제멋대로 활성회되고 
뺨을 대면 꺼진다는 보고도 있었지만 
이것은 하드웨어 문제점이라기 보다는 iOS 소프트웨어 문제점으로 보입니다.  
만일 센서가 전혀 작동되지 않는다면 하드웨어 문제점으로 보는 것이 좋습니다. 


17. 배터리
배터리에 문제점이 없는지 확인하는 방법은 여러가지가 있지만 
가장 널리 사용되는 방법은 배터리가 완전 소진될 때까지 동영상을 돌리는 것입니다. 
애플에 의하면 동영상 배터리가 완전 소진될 때까지 드는 시간은 약 10시간이라고 합니다. 
하지만 결과의 차이는 항상 존재하기 때문에 
디폴트 화면 밝기에서 완충된 아이폰으로 동영상을 돌려서
배터리가 완전 소진되는데 7시간 정도 걸리면 정상으로 볼 수 있습니다.


위의 모든 테스트는 아이폰4 하드웨어에 전혀 해를 주거나 영향을 주지 않는다고 합니다. 
저는 진리의 화이트를 기다리느라 이번 예판은 눈물을 머금고 참여하지 않았지만.. ㅠㅠ
언제 마음이 변할지 모르겠어서.. 열심히 준비하고 있답니다. ^^

아이폰 4가 손에 들어오면 꼼꼼하게 체크해봐야겠습니다. ^^
반응형
Posted by blueasa
, |

Cecil Lew

네트워크 관리 및 워크플로 처리 같은 대부분의 응용 프로그램 유형에는 다이어그램 작성 인터페이스가 필요합니다. 그러나 Windows 응용 프로그램에서 Visio와 같은 다이어그램 작성 인터페이스를 개발하기는 좀처럼 쉬운 일이 아닙니다. 이 기사에서는 Cecil Lew가 UserControl 및 몇 가지 단순한 클래스를 기반으로 하여 간단한 다이어그램 작성 도구를 빌드하는 방법을 소개합니다.

응용 프로그램에서 다이어그램 작성 기능이 필요한 경우에는 어떻게 하시겠습니까? 이 경우 다음과 같은 네 가지 방법이 있습니다. 즉, 1) 타사 라이브러리를 구입하거나 2) Netron 등의 공개 소스 라이브러리를 사용하거나(확장도 가능함) 3) 응용 프로그램을 Visio와 통합하거나 4) 새 도구를 처음부터 빌드하는 것입니다.

1번이 가장 쉽겠지만 타사 지원에 의존해야 하므로 위험도도 가장 높습니다. 2번도 괜찮은 방법 같지만, 개인적으로 이 방법을 사용해 봤는데 솔직히 25,000줄의 코드로 이루어진 다른 사람이 작성한 라이브러리를 확장하는 것은 쉬운 일이 아닙니다. 3번은 Microsoft Office 커뮤니티에서 많은 지원을 받을 수 있으므로 쉽게 수행할 수 있습니다. 그러나 이 경우 응용 프로그램을 통합하려면 대상 컴퓨터에 올바른 버전의 Visio가 설치되어 있어야 한다는 단점이 있습니다. 여기까지 읽으셨다면 제가 개인적으로 4번을 선호한다는 사실을 눈치채셨을 것입니다. Windows Form 및 GDI+에서는 확대/축소, 변환 및 회전 같은 그리기 및 2D 변환에 뛰어난 기능을 제공합니다.

이 기사에서는 이를 검증하기 위해 개발한 간단한 다이어그램 작성 응용 프로그램에 대해 설명합니다. 먼저 클래스 디자인을 중점적으로 설명한 다음 보다 중요한 기능을 자세히 설명합니다. 이 기사에서 설명하는 응용 프로그램은 C# 및 Windows Form을 사용하여 작성되었습니다. 그림 1은 이 응용 프로그램을 보여 줍니다.

그림 1

왼쪽에는 BlockControl 또는 Connector를 오른쪽의 그리기 영역으로 끌어서 놓을 수 있는 도구 상자가 있습니다. 그리고 컨트롤의 텍스트를 두 번 클릭하여 수정할 수 있습니다. 마지막으로 Connector 핸들을 끌어 BlockControl 주위의 핸들 중 하나에 부착할 수 있습니다.

물론 이 응용 프로그램에서 유용한 기능을 많이 제공하는 것은 아닙니다. 그러나 이 응용 프로그램을 통해 다이어그램 작성 프레임워크의 기초가 되는 상속, 컴퍼지션 및 다양한 C# 구문을 사용하는 방법에 대한 기본 개념을 파악할 수 있습니다.

클래스 디자인
DiagramLib 클래스 라이브러리에는 8개의 클래스가 포함됩니다. 표 1에서는 이러한 클래스 및 해당 용도를 나열합니다.

표 1. DiagramLib 라이브러리의 8개 클래스

클래스 목적
Draggable 이 프로젝트에서 발생하는 대부분의 문제는 개체 이동 및 크기 조정과 관련된 것입니다. 이 일반 Draggable UserControl은 마우스 끌기 동작과 위치 변경을 캡처하기 위한 것입니다.
LabelBox 마우스를 두 번 클릭하면 편집 모드로 전환되는 Label 형식 컨트롤입니다. BlockControl 및 Connector 개체가 사용합니다.
ResizeHandle 크기 조정 작업을 처리하는 BlockControl 주위의 작은 사각형입니다.
ConnectorHandle BlockControl 개체 끌기 및 이 개체에 부착하는 작업을 처리하는 Connector 개체 끝점의 작은 사각형입니다.
DiagramControl BlockControl 및 Connector가 상속을 받는 간단한 클래스입니다. "ID" 등의 일반적인 특성을 제공합니다.
BlockControl 텍스트 입력, 이동 및 크기 조정을 위한 주 다이어그램 작성 컨트롤로, Connector 개체와 연결됩니다.
Connector BlockControl 개체를 선 및 화살표와 연결하는 컨트롤입니다.
DrawingBoard BlockControl 및 Connector 개체를 배치하기 위한 화이트보드입니다.

그림 2그림 3에서는 DiagramLib의 클래스 계층 구조 및 이러한 클래스의 구성/연결을 확인할 수 있습니다. 또한 그림 4에서는 보다 뚜렷하게 다양한 클래스 간의 관계를 이해할 수 있습니다.

그림 2

그림 3

그림 4

Connector를 처리하는 방식에는 두 가지가 있습니다. 첫 번째는 다른 다이어그램 작성 컨트롤과 동일하게 취급하는 것입니다. 즉, Connector를 끌거나 크기를 조정할 수 있습니다. 그러나 보다 중요한 것은 Connector를 다른 화면 개체에 연결하지 않아도 된다는 것입니다. Visio에서는 이 방식을 사용합니다. 두 번째 방식을 사용하는 경우 Connector의 양 끝을 항상 무엇인가에 부착해야 합니다. 그러므로 Connector의 끝점이 아무 것에도 부착되지 않은 상태로 둘 수는 없습니다. Netron에서는 이 방식을 사용합니다. 개인적으로는 첫 번째 방식이 두 번째보다 직관적이라고 생각합니다. 그러므로 이 기사의 디자인은 Visio의 방식을 따릅니다.

다음 섹션에서는 클래스 및 여러 클래스를 함께 사용하는 방법에 대해 자세히 설명합니다.

끌기
Draggable 클래스는 UserControl에서 상속되지만 이 클래스에는 시각적인 구성 요소가 없습니다. 이 클래스는 MouseDown 이벤트 다음에 MouseMove 이벤트와 LocationChanged 이벤트가 뒤따르도록 정의되어 있는 마우스 끌기 동작을 처리합니다. 즉, 화면에서 클래스가 실제로 "끌기"되는 것이 아니라 사용자 정의 이벤트인 DraggableMouseMove, DraggableMouseStop 및 DraggableLocationChanged가 발생하는 것입니다. 이 Draggable 개체의 컨테이너가 실제 이동 또는 크기 조정을 수행합니다. 목록 1에는 Draggable 클래스의 세 가지 마우스 이벤트 처리기인 OnMouseDown, OnMouseUp 및 OnMouseMove가 있습니다.

목록 1. Draggable 클래스의 마우스 처리 루틴
 public event MouseEventHandler DraggableMouseMove; public event MouseEventHandler DraggableMouseStop; protected virtual void OnDraggableMouseStop( MouseEventArgs e) { if (DraggableMouseStop != null) { // 대리자를 호출합니다. DraggableMouseStop(this, e); } } protected virtual void OnDraggableMouseMove( MouseEventArgs e) { if (DraggableMouseMove != null) { // 대리자를 호출합니다. DraggableMouseMove(this, e); } } protected virtual void OnMouseDown(Object o, MouseEventArgs e) { IsMouseDown = true; initX = e.X; initY = e.Y; } protected virtual void OnMouseUp(Object o, MouseEventArgs e) { if (IsMouseDown) { MouseEventArgs evt = new MouseEventArgs( e.Button, e.Clicks, e.X - initX, e.Y - initY, e.Delta); OnDraggableMouseStop(evt); } IsMouseDown = false; } protected virtual void OnMouseMove(object o, MouseEventArgs e) { if (IsMouseDown) { // Delta 값(이동한 거리)만 필요합니다. // e.X는 커서의 상대 위치입니다. MouseEventArgs evt = new MouseEventArgs( e.Button, e.Clicks, e.X - initX, e.Y - initY, e.Delta); OnDraggableMouseMove(evt); } }(참고: 프로그래머 코멘트는 샘플 프로그램 파일에는 영문으로 제공되며 기사에는 설명을 위해 번역문으로 제공됩니다.) 

Draggable 클래스에서는 이벤트 처리기를 제공하는 반면 LabelBox 및 ResizeHandle 클래스에서는 시각적 요소 및 이벤트 처리기 간의 링크를 제공합니다. 예를 들어 ResizeHandle에는 마우스 이벤트를 캡처하고 Draggable 마우스 이벤트 처리기에 작업을 위임하는 Label 컨트롤(lblHandle)이 있습니다.

public ResizeHandle() { ... lblHandle.MouseDown += new MouseEventHandler( base.OnMouseDown); lblHandle.MouseUp += new MouseEventHandler( base.OnMouseUp); lblHandle.MouseMove += new MouseEventHandler( base.OnMouseMove); this.LocationChanged += new EventHandler( base.OnLocationChanged); ... } 

앞서 Draggable 클래스에서 컨트롤의 실제 이동을 처리하지 않음을 언급했습니다. 이는 ResizeHandle 또는 LabelBox도 마찬가지입니다. 이러한 클래스는 DraggableMouseMove 이벤트를 상향 전파하여 부모 BlockControl 개체 또는 Connector 개체가 해당 작업을 처리하도록 합니다.

그림 5는 사용자가 ConnectorHandle을 끌면 클래스가 상호 작용하는 방법을 보여 주는 실제 시나리오 다이어그램입니다.

그림 5

부착 및 부착 해제 프로세스(1부): 부착
Connector의 ConnectorHandle을 BlockControl의 ResizeHandle과 아주 가까운 위치로 끌면 부착이 수행됩니다. 반대로 ConnectorHandle을 연결된 BlockControl에서 비교적 먼 위치로 끌면 연결 부착이 해제됩니다. 이 메커니즘을 설명하려면 BlockControl, Connector 및 ConnectorHandle의 구조를 자세히 살펴봐야 합니다.

BlockControl의 중앙에는 LabelBox가 있고 그 주위에는 8개의 ResizeHandle 개체가 있습니다. ResizeHandle 개체에는 그림 6과 같이 0에서 7까지의 인덱스가 지정되어 있습니다.

그림 6

나중에 살펴보겠지만 ConnectorHandle은 BlockControl에 부착되면 이 번호를 기록하기 때문에, ResizeHandle의 인덱스에는 중요한 의미가 있습니다.

Connector에는 각각 반대쪽 끝에 ConnectorHandle 개체가 두 개 있습니다(그림 7 참조).

그림 7

화면에서 ConnectorHandle을 끌면 모든 기존 BlockControl이 호출되어 해당 ResizeHandle 개체 중 ConnectorHandle에 부착될 수 있을 만큼 가까운 위치에 있는 개체가 있는지 확인합니다. BlockControl의 FindHandle 메서드(목록 2 참조)가 특정 지점으로부터 거리를 계산하여 해당 지점이 충분히 가까운 경우에는 ResizeHandle 인덱스를 반환합니다.

목록 2. BlockControl의 FindHandle 메서드
public int FindHandle(Point p) { const int GLUE_DISTANCE = 20; // 길이 20px int x = this.handles[HD_NW].Left; int y = this.handles[HD_NW].Top; int index = 0; double minDist = double.MaxValue; double dist = 0; for (int i = 0; i < NUM_HANDLE; i++) { ResizeHandle hd = this.handles[i]; dist = Math.Sqrt(Math.Pow(hd.Left - p.X, 2) + Math.Pow(hd.Top - p.Y, 2)); if (dist < minDist) { index = i; minDist = dist; } } if (minDist < GLUE_DISTANCE) { return index; } else { return -1; } } 

그림 8에는 BlockControl이 하나만 있지만 실제로 프로그램에서는 화면의 모든 BlockControl 개체를 호출합니다.

그림 8

BlockControl 개체 중 하나에서 유효한 ResizeHandle 인덱스를 반환하는 경우, 이는 Connector가 해당 BlockControl에 즉시 연결되어야 함을 의미합니다. 그러면 ConnectorHandle 위치가 갑자기 변경되어 맞추기 및 붙이기 형식으로 이동합니다.

ConnectorHandle은 ResizeHandle에서 상속되며 BlockControl에 부착되거나 BlockControl에서 부착이 해제되는 기능이 추가됩니다. ConnectorHandle은 BlockControl에 부착되면 BlockControl 이동을 따르며, 그로 인해 부모 Connector 개체의 크기와 모양을 변경합니다. ConnectorHandle은 부착된 BlockControl 및 ResizeHandle을 기억함으로써 이 작업을 수행합니다.

public class ConnectorHandle: ResizeHandle { private BlockControl connectedBlock; private int blockHandleIndex; ... 

부착 및 부착 해제 프로세스(2부): 부착 후 이동
Connector 및 BlockControl이 서로 부착된 후에 BlockControl의 해당 부분을 끌거나 크기를 조정하면 Connector의 크기도 자동으로 조정됩니다. 이는 ResizeHandle에서 LocationChanged 이벤트를 부모 BlockControl로 전송하면 부모 BlockControl은 연결된 모든 Connector가 해당 ConnectorHandle의 위치를 변경하도록 지시하기 때문입니다(그림 9 참조).

그림 9

부착 및 부착 해제 프로세스(3부): 부착 해제
연결된 BlockControl에서 ConnectorHandle을 끌거나 LabelBox 개체를 끌어 중앙에서 다른 위치로 이동하면 부착 해제가 수행됩니다. 이 작업은 끈 위치가 임계값에 도달할 때까지 마우스 이동을 무시함으로써 수행됩니다.

// ConnectorHandle 클래스 protected override void OnMouseMove(Object o, MouseEventArgs e) { if (this.connectedBlock == null) { base.OnMouseMove(o, e); } else { if (ShouldBreakBinding(e)) { connectedBlock.RemoveConnectorHandle( this, blockHandleIndex); connectedBlock = null; base.OnMouseMove(o, e); } } } private Boolean ShouldBreakBinding(MouseEventArgs e) { return (Math.Sqrt(Math.Pow(e.X,2) + Math.Pow(e.Y, 2)) > 20); } 

Connector의 LabelBox 개체를 끌어서 이동해도 역시 양 끝의 연결이 끊어집니다.

// Connector 클래스 private void Label_DraggableMouseMove(Object o, MouseEventArgs e) { // 핸들 중 하나가 Block 컨트롤에 연결되어 있는 경우 // 저항이 필요합니다. if (handles[0].ConnectedBlockControl != null || handles[1].ConnectedBlockControl != null) { double dist = Math.Sqrt(Math.Pow(e.X, 2) + Math.Pow(e.Y, 2)); if (dist <= 20) return; } ... } 

그림
이 섹션에서는 화면에서 컨트롤을 그리는 방법에 대해 자세히 다룹니다. 일부 컨트롤은 Windows Label로 구성되는 ResizeHandle 같은 Windows 기본 요소만으로 이루어져 있습니다. 그리고 GDI+ 라이브러리를 사용하여 화면 업데이트를 수행하는 컨트롤도 있습니다. 여기서는 GDI+ 관련 컨트롤에 대해 주로 설명합니다.

LabelBox 클래스 LabelBox는 개체의 텍스트 설명을 보여 주는 직사각형 상자입니다(그림 4 참조). BlockControl 및 Connector 클래스는 모두 이 클래스를 사용합니다. 이 클래스를 두 번 클릭하면 텍스트 상자가 표시되어 사용자가 내용을 편집할 수 있습니다. 이름에서 짐작되듯이 이 클래스에는 Label 컨트롤이 포함되어 있다고 생각될 수 있습니다. 그리고 이전 버전까지는 실제로 그랬습니다. 그러나 Label 컨트롤은 새로 고침 속도가 매우 느립니다. 화면에서 함께 움직이는 Label 컨트롤이 5개 이상인 경우에는 속도가 너무 느려서 이상하게 보이기도 합니다. 그러므로 이 LabelBox 버전의 경우에는 GDI+ 호출을 통해 직사각형과 텍스트를 다시 그리도록 했습니다.

// LabelBox 클래스 private void LabelBox_Paint(Object o, PaintEventArgs e) { €| e.Graphics.FillRectangle(backgroundBrush, 0, 0, this.Width, this.Height); e.Graphics.DrawRectangle(textPen, 0, 0, this.Width - 1, this.Height - 1); e.Graphics.DrawString(text, txtEdit.Font, textBrush, 2, 2); } 
Connector DrawingBoard 개체는 화면을 새로 고쳐야 할 때 Connector 개체의 Paint 메서드를 호출합니다. ConnectionStyleEnum 속성이 이 클래스에서 설정할 수 있는 스타일을 지정합니다. 이 값과 각 값을 설정했을 때의 효과가 그림 10에 나와 있습니다.

그림 10

LeftRight 및 UpDown 스타일의 경우 정적 다차원 배열을 사용하여 화살표 회전 각도를 결정합니다.

// Connector 클래스 private static int[,] degrees = new int[4,2]; static Connector() { // 화살촉을 그리기 위한 각도 매트릭스를 초기화합니다. // updown, 핸들 1 위에 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.UpDown), Convert.ToInt16(true)] = 0; // updown, 핸들 1 아래 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.UpDown), Convert.ToInt16(false)] = 180; // leftright, 핸들 1 왼쪽에 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.LeftRight), Convert.ToInt16(true)] = -90; // leftright, 핸들 1 오른쪽에 핸들 0 degrees[Convert.ToInt16(ConnectorStyleEnum.LeftRight), Convert.ToInt16(false)] = 90; } 

정적 생성자가 배열 각도를 초기화합니다. 클래스의 정적 생성자는 응용 프로그램 수명 동안 단 한 번만 호출됩니다. 생성자가 트리거되는 때는 클래스의 첫 번째 인스턴스를 만든 때나 정적 멤버가 처음으로 참조되는 때입니다. 화살표의 회전 각도를 확인하려면 치수를 채우면 됩니다.

// Connector 클래스 private void DrawHandlesArrows(Graphics g) { double h0Deg = 0; double h1Deg = 0; switch (connStyle) { case ConnectorStyleEnum.LeftRight: h0Deg = degrees[(int) connStyle, Convert.ToInt16(handles[0].Left < handles[1].Left)]; break; €| } 

화살촉 좌표가 일련의 점으로 기록됩니다. 그림 11그림 12에는 이러한 점이 각각 좌표축 및 화면 좌표로 표시되어 있습니다.

그림 11

그림 12

선 끝에 올바른 각도로 화살촉을 그리려면 세 가지 변환 작업을 수행해야 합니다.

  • 변환 - 화살촉이 중앙(0, 0)에서 약간 벗어나도록 이동합니다. 이 작업은 화살촉이 ConnectorHandle과 같은 영역에 있지 않도록 하기 위해 수행합니다.

  • 회전 - 선 경사도를 기준으로 정확한 각도를 계산합니다.

  • 변환 - 화살촉을 선 끝으로 이동합니다.

다음 코드 세그먼트에서는 화살촉 생성 및 그림 13에 나와 있는 3단계 변환 과정을 설명합니다.

double grad = (float) (handles[1].Top - handles[0].Top) / (float) (handles[1].Left - handles[0].Left); double deg = Math.Atan(grad) * (180 / Math.PI); €| Point[] p = new Point[] { new Point(0, 0), new Point(5, 7), new Point(0, 5), new Point(-5, 7), new Point(0, 0)}; path.AddLines(p); Matrix m = new Matrix(); m.Translate(x, y); // 직선 끝 m.Rotate((float) deg); m.Translate(0, 5); path.Transform(m); 

그림 13

결론
이 기사에서 소개한 8가지 클래스에는 기본적인 기능만이 포함되지만, 이를 기반으로 하여 보다 수준 높은 프레임워크를 만들 수 있습니다. 즉시 사용할 수 있는 라이브러리가 필요한 경우에는 http://netron.sourceforge.net/ (영문)의 공개 소스 Netron 그래프 라이브러리를 확인해 보십시오.

다운로드 단추를 클릭하면 코드(506LEW.ZIP)를 다운로드할 수 있습니다.

Visual Studio .NET Developer 및 Pinnacle Publishing에 대한 자세한 내용을 보려면 해당 웹 사이트인 http://www.pinpub.com/(영문 사이트)을 방문하십시오.

참고: 이 사이트는 Microsoft Corporation 웹 사이트가 아니므로 Microsoft는 그 내용에 책임을 지지 않습니다.

이 기사는 Visual Studio .NET Developer 2005년 6월호를 바탕으로 다시 쓰여진 것입니다. Copyright 2005, by Pinnacle Publishing, Inc., unless otherwise noted. All rights are reserved. Visual Studio .NET Developer는 Pinnacle Publishing, Inc에서 독립적으로 제작한 발행물입니다. 이 기사의 어떤 부분도 Pinnacle Publishing, Inc.의 사전 동의 없이는 어떤 형식으로도(중요한 기사나 논평에서 간략하게 인용하는 경우는 제외함) 사용하거나 복제할 수 없습니다. Pinnacle Publishing, Inc.에 연락하려면 1-800-788-1900으로 전화 주십시오.


 
출처 : http://www.xdotnet.com/xdotnet/board/BoardRead.aspx?F_Code=11&B_Code=1010&B_Index=1280&B_Page=0
반응형
Posted by blueasa
, |

KeyDown이벤트시에 한글 입력은 무조건 229(?)만 나오기 때문에 어떤 글자를 쳤는지는 알 수가 없지요.

 

그래서 한글 입력은 윈도우 메시지를 가로채서 알아냅니다.

 

먼저 윈도우 메시지를 가로채는 방법은 크게 두가지정도를 생각해 볼 수 있겠는데요,

WndProc 메서드를 오버라이드 하는 방법과 IMessageFilter를 구현해서 가로채는 방법이 있겠습니다.

 

인터넷에 찾아보니 WndProc메서드 오버라이드 하는 방법이 나와있는데 전 이 방법으로는 메시지를 가로챌 수 없더군요..

(왜 안되는지 아시는 분은 답글 남겨 주시기 바랍니다..)

음.. 코딩 환경따라 다른지 모르겠습니다.

참고로 제 환경은 Windows XP Pro 이고 .NET FramWork 1.1 Ver 1.1.4322 환경입니다..

 

 

아무튼.. 메시지 필터를 이용해서 메시지를 가로채기 위해서는

윈폼에서 Application.AddMessageFilter(구현한 필터 클래스) 호출하여 가로채는데

다음과 같은 순서로 하면 되겠습니다.

 

1. 메시지를 가로채서 어떻게 처리할 것인지를 구현한다.

즉 IMessageFilter 클래스를 구현하는것을 의미합니다.

 

구체적으로 이런식으로 구현하면 되겠습니다.

 

    public class MyMessageFilter: IMessageFilter

        {

            #region IMessageFilter 멤버

     

            public const int WM_KEYFIRST = 0x100;

            public const int WM_KEYDOWN = 0x100;

            public const int WM_KEYUP = 0x101;

            public const int WM_CHAR = 0x102;

            public const int WM_IME_STARTCOMPOSITION = 0x10D;

            public const int WM_IME_COMPOSITION = 0x10F;

            public const int WM_IME_ENDCOMPOSITION = 0x10E;

            public const int WM_IME_SETCONTEXT = 0x281;

            public const int WM_IME_NOTIFY = 0x282;

            public const int WM_IME_CONTROL = 0x283;

            public const int WM_IME_COMPOSITIONFULL = 0x284;

            public const int WM_IME_SELECT = 0x285;

            public const int WM_IME_CHAR = 0x286;

            public const int WM_IME_KEYDOWN = 0x290;

            public const int WM_IME_KEYUP = 0x291;

            public const int WM_IME_REPORT = 0x0280;

            public const int WM_IME_REQUEST = 0x0288;

            

            public bool PreFilterMessage(ref Message m)

            {

                // TODO:  MyMessageFilter.PreFilterMessage 구현을 추가합니다.

                Form1 fm = (Form1)Form.ActiveForm;

                

                switch(m.Msg)

                {

                    case WM_IME_STARTCOMPOSITION:

                        fm.WriteLine("한글 조합 시작.." + "\t" + m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_IME_COMPOSITION:

                        fm.WriteLine("한글 입력 중.." + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_IME_ENDCOMPOSITION:

                        fm.WriteLine("한글 조합 완료.." + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_IME_SETCONTEXT:

                        fm.WriteLine("WM_IME_SETCONTEXT" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_NOTIFY:

                        fm.WriteLine("WM_IME_NOTIFY" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_CONTROL:

                        fm.WriteLine("WM_IME_CONTROL" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_COMPOSITIONFULL:

                        fm.WriteLine("WM_IME_COMPOSITIONFULL" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_SELECT:

                        fm.WriteLine("WM_IME_SELECT" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_CHAR:

                        fm.WriteLine("WM_IME_CHAR" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_KEYDOWN:

                        fm.WriteLine("WM_IME_KEYDOWN" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_KEYUP:

                        fm.WriteLine("WM_IME_KEYUP" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_REPORT:

                        fm.WriteLine("WM_IME_REPORT" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    case WM_IME_REQUEST:

                        fm.WriteLine("WM_IME_REQUEST" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

     

                    case WM_KEYDOWN:

                        fm.WriteLine("WM_KEYDOWN" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    /*

                    case WM_KEYUP:

                        fm.WriteLine("WM_KEYUP" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                    */

                    case WM_CHAR:

                        fm.WriteLine("WM_CHAR" + "\t"+ m.WParam.ToString() + "\t" + m.LParam.ToString());

                        break;

                }

                

                return false;

            }

     

            #endregion

        }//end of class

 

 

2. 윈폼 클래스에서 구현한 필터 클래스를 선언합니다.

 

private MyMessageFilter mmf = new MyMessageFilter();

 

 

 

3. AddMessageFilter()로 메시지 필터를 윈폼클래스에 등록합니다.

 

Application.AddMessageFilter(mmf);

 

폼 생성자 메서드에서 등록하면 되겠네요..

 

 

참.. 제 소스에서는

윈폼 클래스에 다음과 같은 메서드를 추가했었죠..

 

        public void WriteLine(string str)

        {

            this.textBox1.Text += str + "\r\n";

        }

 

이로서 한글을 입력할때 어떤 메시지가 어떻게 발생하는 지 대충 알 수 있으리라고 생각됩니다.

출처 : Devpia


출처 : http://www.xdotnet.com/xdotnet/board/BoardRead.aspx?F_Code=14&B_Code=1052&B_Index=1294&B_Page=0

반응형
Posted by blueasa
, |

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace QEControls
{
/// <summary>
/// Summary description for FlickerFreeRichEditTextBox.
/// </summary>
public class FlickerFreeRichEditTextBox : RichTextBox
{

// #define WM_PAINT 0x000F

const short WM_PAINT = 0x00f;
const short WM_IME_NOTIFY = 0x0282;
const int IME_CMODE_NATIVE = 0x1;
//const short IMN_SETCONVERSIONMODE = 0x06;
private IntPtr IMN_SETCONVERSIONMODE = new IntPtr(0x06);

public FlickerFreeRichEditTextBox()
{
//
// TODO: Add constructor logic here
//
//SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//SetStyle(ControlStyles.DoubleBuffer , true);
//SetStyle(ControlStyles.UserPaint , true);
_Paint = true;
this.ScrollBars = RichTextBoxScrollBars.Both;
}

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmGetContext (int hWnd);

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmReleaseContext (int hWnd, int hImc);

[DllImport ("imm32.dll", CharSet=CharSet.Auto)]
public static extern int ImmGetConversionStatus (int hImc, out int
fdwConversion, out int fdwSentence);

private bool _isHangulMode = false;
public bool IsHangulMode
{
get { return _isHangulMode; }
}

public bool _Paint = true;
public bool IsPainting
{
get
{
return _Paint;
}
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
if (m.Msg == WM_PAINT)
{
if (_Paint)
base.WndProc(ref m);
else
m.Result = IntPtr.Zero;
}
else if ( m.Msg == WM_IME_NOTIFY )
{
if ( m.WParam == IMN_SETCONVERSIONMODE )
{
int hImc, dwConversion = 0, dwSentense = 0;
hImc = ImmGetContext(this.Handle.ToInt32());
ImmGetConversionStatus(hImc, out dwConversion, out dwSentense);
if ( (dwConversion & IME_CMODE_NATIVE) == 1 )
{ // 한글모드
//System.Diagnostics.Trace.WriteLine("한글모드");
_isHangulMode = true;
}
else
{
//System.Diagnostics.Trace.WriteLine("English Mode");
_isHangulMode = false;
}
ImmReleaseContext(this.Handle.ToInt32(), hImc);
}
}
else
{
base.WndProc (ref m);
}
}

public void BeginUpdate()
{
_Paint = false;
}

public void EndUpdate()
{
_Paint = true;
}
}
}

출처 : http://www.ms-news.net/f2235/iso-8859-1-b-cmljahrlehrcb3i-oscw-mfrimh6ua7a1ltptnku-5396626.html
반응형
Posted by blueasa
, |

한영 변환키 누름 상태는 윈도 메세지에서 WM_IME_NOTIFY 로 확인하는 방법과

WM_KEYUP 이나 WM_KEYDOWN 에서 wParam 에 VK_PROCESSKEY 가

들어오는것으로 확인 할 수 있다.

다만 키를 한번만 누르더라도 WM_IME_NOTIFY 로는 메세지가 여러개가 오는데,

그 중 wParam 이 IMN_SETCONVERSIONMODE 로 한번 오며 이것으로 채크하면 되겠다.

이 중 VK_PROCESSKEY 을 확인하는 방법으로 해 놓았었는데, 이것이 일부 노트북에서

동작하지 않는 것을 발견했다.

2개의 노트북에서 그런 현상이 발견되었으며 그 중 한대를 디버깅 해보았다.

한영키를 누를시 메세지에서 WM_KEYUP 이나 WM_KEYDOWN 은 넘어 오지 않고

WM_IME_NOTIFY 만 넘어오는 것이다.

이런 현상을 놓고 보았을때 WM_IME_NOTIFY 로 확인하는것이 맞겠다.
반응형

'Programming > Win32API' 카테고리의 다른 글

GetAsyncKeyState() 함수와 GetKeyState() 함수의 차이  (0) 2012.06.25
윈도우 투명  (0) 2011.10.30
Keyboard 입력 받기  (0) 2010.09.03
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
Posted by blueasa
, |

속성 -> 링커 -> 최적화 -> 참조 -> 참조하지 않는 데이터 제거

옵션이 켜있다면 말그대로 참조하지 않는 함수도 제거되는데, 만약 아무곳에서도 참조되지 않는 함수에 브레이크 포인트를 걸어놓는다면 디버깅시 비활성화 된다.

때문에 브레이크 포인트가 비활성화 된다면 이것도 염두에 두어야 한다
안그럼 삽질..
반응형
Posted by blueasa
, |

보통 '옵션->디버깅->일반->소스 파일이 원래 버전과 정확하게 일치해야 함' 이 옵션을 제거하면 되는데 그렇게도 되지 않을때가 종종 있다.
1.70 [서명 없는 UTF-8 인코딩 자동 검색] 옵션이 꺼져 있는 Visual Studio 편집기에서 소스 파일에 가비지 값이 보이는 경우가 있을 수 있습니다.
Visual Studio 에서, [도구]->[옵션]->[텍스트 편집기]->[일반]의 [서명 없는 UTF-8 인코딩 자동 검색] 옵션이 기본으로 꺼져 있습니다. [서명 없는 UTF-8 인코딩 자동 검색] 옵션이 꺼져있는 컴퓨터에서는 서명 없는 UTF-8 형식의 파일을 기본 코드 페이지로 열는 경우가 있기 때문에, 편집기에서 가비지가 보일 수 있습니다.

이 문제를 해결하려면

1. [도구]->[옵션]->[텍스트 편집기]->[일반]을 선택한 후 [서명 없는 UTF-8 인코딩 자동 검색] 옵션을 켜십시오. 이 후에도 이 문제가 발생하지 않습니다. 참고. [서명 없는 UTF-8 인코딩 자동 검색] 옵션을 켤 경우, UTF-8 영역과 한국어 (ks_c_5601-1987) 영역에 중복되어 있는 문자들만 파일에 포함되어 있을 경우 서명 없는 UTF-8 파일을 한국어 파일로 잘못 인식하여 가비지가 발생할 수 있습니다.
2. 혹은 해당 파일을 [다른 이름으로 저장]-> [인코딩하여 저장]을 선택하여 서명 있는 UTF-8 파일 형식으로 바꿀 수 있습니다.
내 경우엔 1번 방법으로는 해결되지 않았고 2번으로 해결이 됐었다.
아래 링크를 가보면 여러가지 이슈들이 많다

Microsoft Visual Studio 2005 사용 시 발생하는 문제

반응형
Posted by blueasa
, |

Hello :)

I'm working on a bit of a 2D engine and want it to work with the IME.  Now, normally with a desktop app you don't need any particularly special IME support for an IME to work with your app, you can just start typing in a text box and voila, asian characters (for the most part).  What's actually happening when you're typing asian characters is the IME is drawing windows above your application's window that contains these characters, as I understand it.  In a fullscreen game without typical input widgets, the IME has no idea where to display these windows, and even if it knew where to display those widgets, they wouldn't show up in your fullscreen app.  This means you need to read and send information to the IME directly and take any information you get from it and duplicate what it would've done by itself had you been making a regular desktop app (meaning, draw your own character candidate display, composition display, etc)

My
 2D engine thus far is in .NET 2.0 C# Managed DX.  In the August 2006 SDK, the VC++ DX utility classes contain an example textbox class that contains IME support.  The Managed DX utility classes do not contain any IME support example.  Most of the information I've found by researching around is only for desktop apps that want to extend their support for IMEs beyond the default, rather than support for fullscreen apps.


First I'll lay out what information I've found to be useful in this endeavor:

MSDN: Using an Input Method Editor in a Game (this helps to explain the VC++ DX textbox IME example)
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/Using_an_Input_Method_Editor_in_a_Game.asp

MSDN: Input Method Editor Function Reference
http://msdn.microsoft.com/library/en-us/intl/ime_038z.asp

Header file containing actual enumeration values I didn't find anywhere else
http://www.rpi.edu/dept/cis/software/yesterday/g77-mingw32/include/imm.h

August 2006 SDK C++ DXUT class containing textbox with IME support
C:\Program Files\Microsoft DirectX SDK (August 2006)\Samples\C++\DXUT\Optional\DXUTgui.cpp

Some IME Reference Stuff
http://www.osronline.com/ddkx/appendix/imeimes2_35ph.htm
http://www.osronline.com/ddkx/appendix/imeimes_0h2s.htm

Misc IME Related C# Code
http://www.koders.com/csharp/fidEB8980C0605213D81D1D8364B00F09538F1DF83D.aspx
http://tsuge.astgate.biz/witchgarden/?C%23+Tips%2FWitchPaper%A4%C7%BC%C2%C1%F5%A4%B7%A4%BFIME%C0%A9%B8%E6
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=7712&forum=7

.NET Win32 API Reference Stuff (since you need to use external functions in imm32.dll and user32.dll)
http://www.dotnetwire.com/frame_redirect.asp?newsid=5368
http://www.pinvoke.net/
http://custom.programming-in.net/


So, that's where I'm coming from.  Here's where I'm at.  If you are familiar with the IME language bar, the floating toolbar allows you to select which input language you'd like to use at the moment, along with the input mode.  This input language and other details that you select are context sensitive and will only be used for the window/thread you set them in.  So if you open up Notepad.exe and switch to Japanese input, you'll have Japanese input available in Notepad, but if you switch to another Notepad.exe that you happened to have open, you'll still be in English language mode (until you set it to Japanese also).

Now, if you click somewhere on an app that isn't a textbox, so you have no text entry area selected while you're in Japanese input mode, you'll notice all of the icons on the IME language bar go disabled, naturally, because you can't input anything, so it won't bother trying to handle any input or send any characters.  The second you select a text entry area, bam, those icons become available again.

When I run my 2D engine in windowed mode and watch the IME language bar, I can use the ALT+SHIFT hotkey to switch language modes and receive that window message via WndProc, allowing me to spew text in my engine that says what the current input language is set to, but all of the language bar icons are disabled.  This is common sense and is expected.

The problem is, so far I have had no luck in getting the IME to recognize the input context and accept my commands to it to switch the ConversionStatus or even to begin it's composition string for me to detect. I'm not sure if I have to tell it to start a composition string and then it notifies the window back that it's starting, or if I just wait, but it won't bother starting any composition string until it's even in the right conversion mode (I imagine).

So now, I will refer to an area of the MSDN: Using an Input Method Editor in a Game (link above) article that has been stuck in my head.

"A full-screen application must properly handle the following IME-related messages:

"
I am handling WM_INPUTLANGCHANGE(via the .NET built in OnInputLanguageChange) and WM_IME_SETCONTEXT.  The other messages I won't receive until the IME is ready to do something, and so far I haven't gotten the IME to be ready to actually do anything :). I am sure there's more I need to do than just get these basic messages and respond to them, because it doesn't seem to be doing much.  If anyone knows anyone who might be able to point me in the right direction, it would be magically delicious.


For now, here is some of the code.  I have created a namespace called External that has a class called IME in it.  So IME.Something is referring to stuff in this class.  I have all of the dll imports and struct values contained in it.

// Incoming Window Message Events
protected override void WndProc(ref Message m) {
   switch ((IME.Message)m.Msg) {
      case IME.Message.WM_IME_SETCONTEXT:
         IME.imcHandle = IME.ImmGetContext(this.Handle);
         USER32.SendMessage(IME.imcHandle, m.Msg, m.WParam, IntPtr.Zero);
         IME.ImmReleaseContext(this.Handle, IME.imcHandle);
         break;
   }

   base.WndProc(ref m);
}

// OnInputLanguageChanged Event
protected override void OnInputLanguageChanged(InputLanguageChangedEventArgs e) {

   // Get IMC Handle
   IME.imcHandle = IME.ImmGetContext(this.Handle);

   // Get language and layout details
  
keys.languageFullName = e.InputLanguage.Culture.EnglishName;
   keys.languageShortName = e.InputLanguage.Culture.TwoLetterISOLanguageName;
   keys.layoutID = e.InputLanguage.Culture.KeyboardLayoutId;

   // Get current Conversion and Sentence Modes into IME.current*
  
IME.ImmGetConversionStatus(IME.imcHandle,ref IME.currentConversionMode,ref IME.currentSentenceMode);

   if (IME.currentConversionMode == 0 && keys.languageShortName == "ja") {
      IME.currentConversionMode = (int) IME.ConversionMode.IME_CMODE_NATIVE;
      IME.currentSentenceMode = (int) IME.SentenceMode.IME_SMODE_AUTOMATIC;

      IME.ImmSetConversionStatus(IME.imcHandle,(int)IME.ConversionMode.IME_CMODE_NATIVE | (int) IME.ConversionMode.IME_CMODE_FULLSHAPE, (int)IME.SentenceMode.IME_SMODE_AUTOMATIC);

   }

   if (IME.currentConversionMode != 0 && keys.languageShortName == "en") {
      IME.currentConversionMode = 0;
      IME.currentSentenceMode = (int) IME.SentenceMode.IME_SMODE_NONE;

      IME.ImmSetConversionStatus(IME.imcHandle, (int) IME.ConversionMode.IME_CMODE_ALPHANUMERIC, (int) IME.SentenceMode.IME_SMODE_NONE);

   }

   // Release IMC Handle
   IME.ImmReleaseContext(this.Handle, IME.imcHandle);

   base.OnInputLanguageChanged(e);

}


Of course that is only a very small portion of code that will be necessary for this whole thing to work when it's complete.  I'll also restate, I do not expect this code to do what I'm after, I'm looking for info on what to do next in order to achieve the desired result.  I've tried a couple things, but if anyone has done this before or has further insight, it would sure speed things up.  I imagine it's something very simple.

-Crache


출처 : http://social.msdn.microsoft.com/forums/en-US/gametechnologiesdirectx101/thread/32e53d65-4f99-4e47-9207-7254a96af33e/

반응형
Posted by blueasa
, |

기본적인 키보드 메시지

윈도우즈에서 한글을 고려하지 않고 키보드 입력을 다루는 방법은 정말 쉽다.

Windows는 키보드 입력이 들어올 때 마다 현재 입력 포커스를 가지고 있는 윈도우에게로 아래 메시지를 보내준다.

메시지

내용

WPARAM

LPARAM

WM_CHAR

문자가 조합된 경우

조합된 글자
(TCHAR형으로 넘어옴)

0~15: 반복 횟수
16~23: 스캔 코드
24: 확장 키가 눌렸는가?
29: alt키가 눌려졌는가
30: 이전에 눌려진 상태로 있었는가?
31: 아직 눌려진 상태로 있는가?

WM_KEYDOWN

키보드에서 키가 눌려짐

눌러진 virtual key

동일

WM_KEYUP

키보드에서 키가 눌려졌다 떼어짐

떼어진 virtual key

동일

WM_SYSKEYDOWN

Alt키가 눌려진 상태에서 키가 눌려짐

눌러진 virtual key

동일, 29번 비트는 항상 1

WM_SYSKEYUP

Alt키가 눌려진 상태에서 키가 떼어짐

떼어진 virtual key

동일, 29번 비트는 항상 1

위의 표에서 대부분은 자명한 것이다. 이 중 몇 가지 사항만 짚고 넘어가면 된다.

가장 먼저 이야기 해야 할 것이 WM_CHAR 메세지 이다. 이 메시지는 메인 루프의 TranslateMessage(&msg)에 의해 생겨나는 것이다. 이 함수는 MSG msg 구조체 내의 message, wParam, lParam 멤버와 time멤버를 분석하여 WM_KEYDOWN과 WM_KEYUP으로부터 적당한 갯수의 WM_CHAR를 만들어 낸다. 이 때, 제어판에서 설정한 키 입력 반복 속도 정보가 사용된다.

다음으로 기억해야 할 것은 TCHAR형이다. TCHAR를 알기 전에 WCHAR를 알아야 한다. Win32 API는 유니코드를 지원한다. 2바이트 유니코드 문자 한개를 저장하는 자료형이 WCHAR이다. 다음은 각각 유니코드를 사용하지 않는 소스 코드와(이러한 방식의 한글 표현을 Double Bytes Character Set, DBCS라고 한다) 유니코드를 사용하는 소스 코드를 보여준다.

DBCS 방식

	char a[] = "안녕하세요";
	cout << strlen(a); /* 아마 10이 출력될 것이다 */

유니 코드 방식

	WCHAR w[] = L"안녕하세요";
	cout << wcslen(w); /* 아마 5가 출력될 것이다 */

만일 DBCS 방식으로 작성된 코드를 아시아권 국가에 배포하기 위해 유니코드 방식으로 바꾸려면 어떻게 하면 될까? 혹은 유니코드를 지원하는 소스 코드를 유니코드를 필요로 하지 않는 사용자들을 위해(대신 코드는 가벼워질 것이다) DBCS 방식으로 바꾸려면 어떻게 하면 될까? 아래와 같이 코딩하면 이를 간단히 할 수 있다.

	#define _UNICODE /* 만일 유니코드를 사용하고 싶으면 이 문장을 추가하고 아니면 이 문장을 빼시오 */
	TCHAR w[] = _T("안녕하세요");
	cout << _tcslen(w); 

만일 유니코드를 사용하고 싶지 않으면 #define _UNICODE를 지우면 된다. 이것은 의 구현이다. 내부적으로는 다음과 같이 구현되어 있다.

	#ifdef _UNICODE 
		typedef WCHAR TCHAR;
		#define _T(x) L##x
		#define _tcslen wcslen
	#else
		typedef char TCHAR;
		#define _T(x) x
		#define _tcslen strlen
	#endif

_T(x) 매크로를 정의할 때 ANSI C의 토큰 페이스트 ##가 사용되었다. 이 매크로는 "abc"를 L"abc"로 바꾸어야 하지만(떼어서 쓰면 안되고 반드시 붙여서 써야함), #define _T(x) Lx라고 할 수 도 없지 않은가? ##기호는 L과 x가 서로 다른 기호라는 것을 알려준다.

_T 매크로 대신 __TEXT, _TEXT, TEXT, __T를 사용하여도 동일한 결과를 얻을 수 있으며, 실제로는 _tcslen보다 Windows API 함수인 lstrlen, lstrcmp, lstrcpy 등이 훨씬 많이 사용된다.

정리하면 우리가 _UNICODE를 define 했는가 아닌가에 따라서 윈도우즈는 때때로 char형을, 때때로 WCHAR 형을 WM_CHAR 메세지의 wParam으로 넘겨줄 것이다.

마지막으로 virtual key에 대해 이야기해 보자. 각각의 키보드는 눌려지거나 떼어졌을 때 컴퓨터로 눌려지거나 떼어진 키 번호를 보낸다. 이 키 번호를 'scan code'라고 한다.^^;; 그러나 scan code는 키보드 종류에 따라 다르다. 따라서 윈도우즈는 응용 프로그램 제작자들의 편의를 위해 이 스캔 코드를 virtual key로 바꾸어준다.

이러한 서비스는 아주 편리하다. 분명히 모든 키보드에에서 현재 내 오른쪽 새끼손가락 근처에 있는 엔터키와 Numpad에 있는 엔터키의 스캔 코드는 다르다. 그러나 어느 경우나 WM_KEYDOWN 메시지에는 VK_RETURN으로 들어올 것이다.(그리고 WM_CHAR 메시지에는 '\r' 문자가 들어올 것이다)

키 코드

내용

실제 값

VK_CANCEL

Ctrl+Break를 눌렀을때

03

VK_BACK

Backspace 키

08

VK_TAB

Tab키

09

VK_RETURN

Enter 키

13

VK_SHIFT

Shift키

16

VK_CONTROL

Ctrl 키

17

VK_MENU

Alt 키

18

VK_CAPITAL

Caps Lock 키

20

VK_ESCAPE

Esc 키

27

VK_SPACE

Space 바

32

VK_PRIOR

Page Up 키

33

VK_NEXT

Page Down 키

34

VK_END

End 키

35

VK_HOME

Home 키

36

VK_LEFT

좌측 화살표

37

VK_UP

위쪽 화살표

38

VK_RIGHT

우측 화살표

39

VK_DOWN

아랫쪽 화살표

40

VK_INSERT

Insert키

45

VK_DELETE

Delete키

46

VK_F1 ~ VKF10

F1~F10

112-121

VK_NUMLOCK

Num Lock

144

VK_SCROLL

Scroll Lock

145

Windows에 운영체제의 성능에 대해서 못마땅해 하는 사람들은, 이러한 다대일 대응이 문제를 일으키기를 기대할 수 도 있다. 예를 들어 Numpad의 4, 6, 8, 2는 게임등에서 왼쪽, 오른쪽, 위, 아래를 나타내는데 사용될 수 있지만, 이것이 키보드의 숫자가 눌려졌을 때도 작동한다는 것은 비극적인 일이다. 그러나 설마 그 정도로 어정쩡 하겠는가? 전자의 경우 lParam의 24번째 비트(확장 키가 눌렸는가?)는 1이 되고, 후자의 경우는 0이 된다.

캐럿

캐럿과 관련되어 용어상 분명히 해 두어야 할 것이 있다. 캐럿은 커서가 아니다. 여러분이 워드 프로세서나 메모장 등을 띄웠을 때 여러분의 입력을 기다리는 깜박이는 것이 캐럿이다. 그렇다면 커서는 무엇이란 말인가? 여러분이 책상 위에서 마우스를 움직일 때 모니터 상에서 따라 움직이는 화살표가 바로 커서이다. WNDCLASS를 만들 때 LoadCursor(NULL, IDC_ARROW);를 했던 사실을 잊었는가?

Win32에서 캐럿을 다루는 함수는 다음과 같다.

  • 캐럿을 생성: CreateCaret(HWND hwnd, HBITMAP hBitmap, int width, int height)
  • 캐럿을 보임: ShowCaret(HWND hwnd)
  • 캐럿의 이동: SetCaretPos(int x, int y)
  • 캐럿을 숨김: HideCaret(HWND hwnd)
  • 캐럿을 파괴: DestroyCaret()

응용 프로그램 범위에서 캐럿을 단 한 개만 생성할 수 있음에 주의하라. 오직 하나의 윈도우만이 캐럿을 가져야 한다. 가장 좋은 방법은 WM_SETFOCUS에서 캐럿을 생성하고, WM_KILLFOCUS에서 캐럿을 삭제 하는 것이다. 이 두 메시지는 반드시 쌍으로 불려지므로 메모리상을 둥둥 떠다니는 캐럿을 걱정할 필요는 없다.

또한 HideCaret을 10번 호출했으면, ShowCaret을 10번 호출해야 캐럿을 볼 수 있음을 주의하라. 캐럿은 암기력이 좋은 친구이다.

IME 메시지

한글 Windows를 비롯한 DBCS을 사용하는 국가의 윈도우즈에는 여러개의 키보드 입력이 한 개의 글자를 만드는 일을 관리해 주는 IMM(Input Method Manager)이 내장되어 있다. 키보드에서 문자가 입력되면 IMM이 여러분의 입력을 가로채서 한 글자가 완성되었을 때 비로소 WM_CHAR 메시지를 보내준다.

여러분의 프로그램이 IMM을 무시한채, 단지 WM_CAHR 만을 처리하더라도, 여러분의 프로그램은 대부분의 경우에 잘 작동할 것이다.(잠시후에 왜 잘 작동하는가를 알게 된다)그러나 한 글자가 완성되었을 때 비로소 화면에 나타나는 그런 프로그램이 아니라 한 개의 자모 단위로 입력되고 지워지는 과정을 전부 처리할 수 있는 프로그램을 작성하고 싶다면, IMM이 보내는 IME(Input Method Editor) 메시지들을 핸들링하라.

이 절에서는 IME 메시지들을 알아보고 다음 절에서 한글 타자 연습 프로그램을 만들 것이다. 만일 여러분이 프로그램에서 IMM을 다루고 싶다면, Project 메뉴의 Setting에서 imm32.lib를 링크에 추가하고 소스 코드에는 를 include 해야 한다.

다음은 기본적인 IME 메시지들이다.

메시지

내용

WM_IME_KEYDOWN

쉬프트+스페이스나 한글키와 같은 IME 관련 키가 눌려졌을 때 IMM에의해 보내지는 메시지이다. 이 메시지 DefWndProc에 넘기면 그에 해당하는 WM_KEYDOWN이 불린다.

WM_IME_KEYUP

쉬프트+스페이스나 한글키와 같은 IME 관련 키가 떼어졌을 때 IMM에의해 보내지는 메시지이다. 이 메시지를 DefWndProc에 넘기면 그에 해당하는 WM_KEYUP이 불린다.

WM_IME_CHAR

문자가 조합이 끝났을 때 IMM에의해 보내지는 메시지이다.

만일 _UNICODE가 #define되어 있다면 WM_IME_CHAR는 디폴트 동작으로 한번의 WM_CHAR를 발생시키고 wParam에 WCHAR형의 글자를 넘긴다. 만일 _UNICODE가 #define되어있지 않다면, WM_IME_CHAR는 디폴트 동작으로 두 번의 WM_CHAR를 발생시키고 wParam으로는 상위바이트, 하위바이트를 차례대로 넘긴다.

만일 입력이 들어오면 배열에 문자를 저장하는 코드가 있다면, 이 코드가 한글과같은 Double Bytes Character를 고려하지 않고 작성되었더라도, 한글이 입력되었을 때는 두 번의 WM_CHAR가 차례로 상위바이트, 하위 바이트를 넘기므로, 아무런 문제 없이 작동할 것이다. 많은 외국 회사에서 작성한 에디터나 텔넷 프로그램들이 한글 Windows에서 그렇게 작동하고 있는 것이다.

그러나 위에 소개한 세 개의 IME 메시지보다 더 중요한 메시지들이 있다.

메시지

의미

WM_IME_STARTCOMPOSITION

문자가 조합이 시작

WM_IME_COMPOSITION

문자가 조합 중

WM_IME_ENDCOMPOSITION

문자가 조합이 끝남

WM_IME_STARTCOMPOSITION과 WM_IME_ENDCOMPOSITION 메시지는 한글 조합이 시작할 때와 끝났을 때 알려주는 메시지이며, 필요하지 않으면 대게의 경우 DefWndProc로 넘겨진다. 그러나 WM_IME_COMPOSITION 메세지는 한글모드에서 한글이 조합되는 중 발생하므로 만일 완전한 조합이 되지 않은 글자의 출력을 원한다면 반드시 처리해야 한다.

WM_IME_COMPOSITION이 발생하면 lParam의 값을 검사해서 현재 글자가 확정되었는지 확정되지 않았는지 알수 있다. 이 때 wParam으로는 새로 추가된 글자가 넘어오지만 대부분의 경우 ImmGetCompositionString 함수를 호출하여 현재까지의 변경된 버퍼 상태를 얻어오는 것이 일반적이다. 다음은 키보드 입력에 따른 Composition 버퍼의 내용이다.

입력순서 lParam의 내용 Composition 버퍼의 내용
GCS_COMPSTR
GCS_COMPSTR
GCS_COMPSTR
GCS_RESULTSTR
GCS_COMPSTR
GCS_COMPSTR
GCS_RESULTSTR
GCS_COMPSTR
3 GCS_RESULTSTR 다3

다음은 사용자가 backspace를 눌러 조합중인 음소를 지우는 경우이다.

입력순서 lParam의 내용 Composition 버퍼의 내용
GCS_COMPSTR
GCS_COMPSTR
Back Space GCS_COMPSTR
Back Space GCS_COMPSTR NULL (길이 0)

위의 표를 잘 분석해 보면, 우리는 lParam에 GCS_COMPSTR이 들어올 때는 캐럿 위치를 증가시키지 않고 단지 Composition 버퍼의 내용을 현재 캐럿 위치에 출력하고, lParam에 GCS_RESULTSTR이 들어오면 이 때는 WM_CHAR 또한 불릴 것이므로 WM_CHAR에서 글자를 출력하고 캐럿 위치를 이동하여야 함을 알 수 있다.

마지막으로 IMM의 상태가 변경되었을 때 우리에게 알려주는 메시지를 알아보고 이 절을 마치도록 하자.

메시지

내용

wParam

WM_IME_NOTIFY

IMM의 상태가 바뀔 때

글자 입력창 관련

IMN_OPENCANDIDATE
IMN_CHANGECANDIDATE
IMN_SETCANDIDATEPOS
IMN_CLOSECANDIDATE

상태 창 관련

IMN_OPENSTATUSWINDOW
IMN_SETOPENSTATUS
IMN_SETSTATUSWINDOWPOS
IMN_CLOSE_STATUSWINDOW

문자 조합 관련

IMN_SETCOMPOSITIONFONT
IMN_SETCOMPOSITIONWINDOW

모드 관련

IMN_SETCONVERSIONMODE
IMN_SETSENTENCEMODE

예를 들어 한/영 상태가 변경될 때 마다 상태바에 한/영 상태를 표시해 주고 싶다면 WM_IME_NOTIFY에서 wParam이 IMN_SETCONVERSIONMODE가 들어올 때 현재 IME 상태를 얻어 상태바에 표시해 주면 된다. 다음은 현재 IME 상태를 얻어오는 코드이다.

	DWORD dwConversion, dwSentence; /* 현재의 IME 상태가 저장될 곳이다 */
	HIMC himc = ImmGetContext(hwnd); /* 현재 input context의 핸들을 얻어 온다 */
	ImmGetConversionStatus(himc, &dwConversion, &dwSentence); /* 현재 IME 상태를 얻어 온다. */
	ImmReleaseContext(hwnd, himc); /* input context의 핸들을 반납한다 */

출처 : http://cafe.naver.com/cyberzone.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=400
반응형

'Programming > Win32API' 카테고리의 다른 글

윈도우 투명  (0) 2011.10.30
한영키 누름 윈도우 메세지 확인 관련  (2) 2010.09.06
IME 영문만 입력가능하게 하기  (0) 2010.09.03
IME  (0) 2010.09.02
getClienteRect 와 getWindowRect  (0) 2010.08.31
Posted by blueasa
, |