[Visual Studio] 유용한 단축키 이름 Lu's…〃 Programing。

Visual Studio 2019를 튜닝하다가 나부터 기억에 남으라고 기록해보는 단축키 이름 목록이다.
[도구 > 옵션 > 키보드]에서 해당 키워드를 입력하여 단축키를 확인 또는 변경할 수 있다.



1. 편집.일치하는다음캐럿삽입

visual studio code에서 신나게 쓰던 기능. 2019는 확인했는데 2017은 확인 안 해봄.
2017에도 있던 기능이니까 되지 않을까? 

기본 단축키: Alt + Shift + .

개인적으로는 Ctrl + W로 바꾸면 사용 중이다.


2. 편집.선택영역서식

visual studio 2013부터는 붙여넣을 때 자동으로 설정해둔 서식(vs 내장 서식 또는 clang-format 등)으로 자동으로 코드를 포매팅하는데 그걸 수동으로 하고 싶을 때 사용한다.

기본 단축키 : Ctrl + K, Ctrl + F

요새야 뭐... 그냥 Ctrl + X 누르고 Ctrl + V 누르면 되지만..


3. 빌드.선택영영빌드

컴파일(F7 또는 Ctrl + F7)또는 솔루션 빌드(Ctrl + Shift + B)를 알고 있어도 은근히 모르는 기능인데, 이 기능은 무려! 현재 프로젝트만 빌드해준다. 기본 값은 잘 모르겠는데 나는 Ctrl + B로 해두고 쓴다.



4. 
편집.복사
편집.붙여넣기
편집.잘라내기

잘 모르던데, 영역을 잡지 않고 Ctrl + C 또는 Ctrl + X를 하면 줄 전체가 복사 또는 잘라내기가 실행된다. 붙여넣을 경우 현재 캐럿의 윗줄에 줄을 추가해 붙여넣는다. 이거 생각보다 모르더라. 생산성의 급이 달라지는 단축키.


5. 편집.줄삭제

Ctrl + X가 있으면 빈 줄을 쉽게 삭제할 수 있는데 그 경우 클립보드 내용이 날아간다는 문제가 있다. 줄삭제는 단순히 줄만 날려준다!


6. 
편집.선택한줄위로이동
편집.선택한줄아래로이동

생산성의 급을 한 단계 올려주는 두 번째 비법. 이거 알면 줄 복사해서 붙여넣는 일 따윈 하지 않는다.

기본 단축키 : Alt + ↑ / Alt + ↓


7.
편집.위로줄스크롤
편집.아래로줄스크롤

6번 해보다가 7번을 알게 되는 사람도 많은데, 그다지 의미 없는 단축키처럼 보이지만 나중에 보면 효자손같은 역할을 한다. 

기본 단축키 : Ctrl + ↑ / Ctrl + ↓


8. 편집.정의피킹

정의로 이동(F12)은 잘 알지만 정의피킹 단축키를 잘 모르는 사람이 많더라. 어지간히 작은 화면이 아니면 정의피킹이 더 나은 경우가 많다. 

기본 단축키 : Alt + F12


9. 디버그.시작

무려 F5라는 단순한 키로 디버그.디버그하지않고시작(Ctrl + F5)보다 누르기 더 쉬워요! 그러니까 좀 디버깅 해라...

"조교님, 이거 안 돼요!"
"디버깅해보시죠"
Ctrl + F5
"하... 씁... 다시 해보세요."
"아, 네, 죄송합니다..."
Ctrl + F5
"..."

9-1. 디버그.그래픽디버깅시작

DirectX 좀 만졌다 싶으면 그래픽 디버깅으로 내가 렌더타겟에 잘 그린 기린 그림 그리고 있나 봐야하는데 Visual Studio에서 그런 궁금증을 단박에 해결할 디버깅 툴을 지원합니다! 사용법은 처음 보면 난해하겠지만 어쨌든 좋음.

기본 단축키 : Alt + F5



10.
편집.다음단어로
편집.이전단어로

이건 대충 경험적으로 체득하던데 Ctrl + 좌우 화살표로 단어 단위로 이동하는 기능. Shift 누르면 영역 선택도 가능하다. 왠만하면 알아서 습득하더라.

기본 단축키 : Ctrl + ← / Ctrl + →
영역 선택 : Ctrl + Shift + ← / Ctrl + Shift + →


11.
창.다음문서창으로이동
창.이전문서창으로이동

마우스를 멀리하고 싶을 때 유용한 탭 이동 단축키. 참고로 웹페이지도 이걸로 탭 이동 가능함.

기본 단축키 : Ctrl + Tab
거꾸로 : Ctrl + Shift + Tab


11-1.

참고로 탭 창 뜨면 키보드로 이동 가능하다.



-------------------

 개발 툴을 바닐라로 쓰는 사람도 있지만, 바닐라로 쓰더라도 몇 번 쓰고 안 쓸 게 아니라면 생산성에 도움이 되는 단축키는 외워두면 쓸모가 크다. 한 번쯤은 자기가 원하는 기능을 찾아서 익혀보는 노력을 해보자.




ps. 기능 이름 찾는 방법

위에 메뉴보면 키보드로 할 수 있는 명령들의 이름이 이렇게 보인다.

[편집 > 고급 > 선택한 줄 위로 이동]이라면 [편집.선택한줄위로이동]이 명령키워드가 되는 셈. [도구 > 편집 > 키보드]에서 '선택한줄'만 쳐도 관련 명령들이 나오니까 한 번 쯤 찾아보자.

[Direct2D/DWrite]설치되지 않은 폰트 설치하지 않고 사용하기 Lu's…〃 Programing。

AddFontMemResourceEx DWrite CreateTextFormat 등에서 적용되지 않는다.

 

DWrite CreateTextFormat 함수는 번째 인자로 fontCollection 받는데, 값이 nullptr이면 시스템 폰트에서 번째 인자로 주는 fontFamilyName 검색한다.

 

DWrite에서 시스템 폰트 이외의 폰트를 사용하는 방법은 폰트 컬렉션을 만드는 방법이다.

 

폰트 컬렉션을 만드는 방법은 크게 가지로 나눌 있는데, 하나는 Windows 10 이상의 환경에서만 사용 가능한 방법과 이전의 버전에서 사용 가능한 방법이다.

 

 

 

  1. Windows 10 이전 버전 호환을 위한 방법

 

Windows 7/8.1에서 사용되는 방법은 Windows 7 Windows SDKSample에 있는데… 지금 찾아보니 페이지가 중국 MS 기술문서 말고는 누가 Github 아카이빙한 말고는 찾겠더라.

 

https://github.com/pauldotknopf/WindowsSDK7-Samples/tree/master/multimedia/DirectWrite/CustomFont

 

예제는 폰트 파일에서 불러오는 아니라 .rc 파일에 있는 폰트를 불러오는 시나리오다. 만약 폰트를 파일에서 불러오고 싶으면 CreateFontFileReference 함수를 써서 reference key 알아낸 이를 사용하여 CreateCustomFontFileReference함수를 호출하여 custom file file reference 만드는 방법이 있다. 만약 rc 파일을 사용한다면 과정은 생략해도 된다.

 

 간단한 스텝에 대해 설명하자면,

 

  1. ResourceFontContext 객체를 선언한다.
     
  2. CreateFontCollection 함수를 호출한다.
    번째 인자는 Font Collection Key이고 번째 인자는 key size이다.

    여기서 알아둘 점은, key 리소스 ID 또는 CustomFontFileReference에서 설정한 ID 값이다.
     
  3. 번째 인자로 넘긴 fontCollection 객체를 활용하여 폰트를 만든다.

 

 

 

방법이 귀찮고 어려운 이유는, CustomFontCollection만들기 위해 필요한 IDWriteFontCollectionLoader 객체를 결국 사용자가 직접 구현을 줘야 한다는 점이다.

 

이러한 문제는 Windows 10 되면서 매우 간단하게 해결이 되었다.

 

 

 

  1. Windows 10 이상의 버전에서 사용하는 방법

 

말도 필요 없을 정도로 간단해졌다.

 

Windows 10부터 추가된 IDWriteFactory3 객체에FontSet 관련 API 들어가서, 더는FontCollectionLoader 객체를 직접 만들어줄 필요가 없어졌다.

 

사실 버전의 폰트 추가 방법에 대해서는 MS 공식문서가 되어 있어서 굳이 포스팅할 필요는 없지만, 간단히 소개해보자 한다.

 

우선 공식 문서 : https://docs.microsoft.com/en-us/windows/desktop/directwrite/custom-font-sets-win10

 

이번에는 리소스에 저장된 폰트는 설명을 생략한다. 공식 문서의 InMemoryFont 참고.

https://docs.microsoft.com/en-us/windows/desktop/directwrite/custom-font-sets-win10#creating-a-custom-font-set-using-font-data-loaded-into-memory

 

 

그리고 포스트에서 설명하는 IDWriteFactory5 객체에 대해서이다. IDWriteFactory3 객체에 대해서는 공식 문서를 참고하기 바란다.

 

가지 필요한 클래스들을 열거해보겠다.


IDWriteFontFile

FontFileReference 얻기 위해 필요한 객체

IDWriteFontSetBuilder1

FontFile 추가하여 FontSet 만드는 Builder 객체

IDWriteFontSet

FontCollection 바꿔먹을

 

최종적으로 FontCollection 만들어지면 개의 객체는 유지되지 않아도 괜찮다. , InMemoryFont 위한 IDWriteInMemoryFontFileLoader 객체의 경우에는 따로 가지고 있다가 객체 소멸 UnregisterFontFileLoader 호출해야한다.

 

 

 

아까 Windows 7/8.1과는 다르게 정말 편해졌다.

 

  ComPtr<IDWriteFontFile> fontFileReference;

 dwFactory->CreateFontFileReference(L"MyFont.ttf", nullptr, &fontFileReference);
 
 ComPtr<IDWriteFontSetBuilder1> fontSetBuilder;
  dwFactory->CreateFontSetBuilder(&fontSetBuilder);
 
  fontSetBuilder->AddFontFile(fontFileReference.Get());
 
 ComPtr<IDWriteFontSet> customFontSet;
  fontSetBuilder->CreateFontSet(&customFontSet);
 
  dwFactory->CreateFontCollectionFromFontSet(

       customFontSet.Get()

    , &m_pdwFontCollection

    );

 

 

 

+) 추가

 

이렇게 추가한 폰트의 이름을 모를 있다. 예를 들어 "TFont"인줄 알았는데 "Test Font"라고 입력해야만 해당 폰트를 찾을 수도 있고. 이럴 때를 위한 폰트 이름을 찾는 방법이다.

 

여기서 폰트이름을 TCHAR[65] 설정했는데, 사실 이건 내가 몰라서 이렇게 지은 것이다. 수도 있다. 적절히 정하자.

 

원리는 단순하다. 아까 만든 FontCollection에서 FontFamily 얻어내 이름들을 얻어올 것이다.

 

  ComPtr<IDWriteFontFamily> fontFamily;
 ComPtr<IDWriteLocalizedStrings> localizedFontName;
 TCHAR c_styleFontName[65];

  m_pdwFontCollection->GetFontFamily(0, &fontFamily);
  fontFamily->GetFamilyNames(&localizedFontName);
  localizedFontName->GetString(0, c_styleFontName, 65);

 

만약 여러 개의 폰트를 FontCollection 추가했다면, FontCollection GetCount 등의 함수가 있으니 적절히 참고하자.

 


[winapi] 설치되지 않은 폰트 설치하지 않고 사용하기 미분류

 CreateFont 기본적으로 시스템에 설치된 폰트를 찾는다. 하지만 사용자가 무슨 폰트를 설치했는지도 모르고, 그렇다고 함부로 사용자 컴퓨터에 ' 폰트 설치해주세요 ㅎㅎ' 할 수 없다. 당장 대부분의 프로그램에서 사용자가 설치하지 않은 폰트로 프로그램에 글자를 적는다. 어떻게?

 

 당연히 MS에서는 이에 대한 방법을 모두 구현해 두셨고, 포스트를 찾는 사람이라면 방법을 찾았거나 너무 어려워서 간단한 샘플을 원하리라 생각한다.

 

일단 windows GDI부터 확인해보자.

 

GDI에서는 관련된 함수가 개다.

 

AddFontMemResourceEx

 

RemoveFontMemResourceEx

 이름도 정말 정직하다. 메모리 영역에 폰트를 추가한다는 뜻이고, 프로그램이 종료되면 폰트는 사용할 없게 된다. 해제 역시 하면 좋지만 하지 않더라도 프로그램이 종료하며 동시에 해제된다.

 

사용 방법은 간단한 편이다. AddFontMemResourceEx 인자는 4개인데, 다음과 같다.

 

HANDLE AddFontMemResourceEx(

PVOID pFileView,

DWORD cjSize,

PVOID pvResrved,

DWORD *pNumFonts

);

 

출처:<https://docs.microsoft.com/ko-kr/windows/desktop/api/wingdi/nf-wingdi-addfontmemresourceex>

 

자세한 인자 설명은 출처를 참고하면 된다. 간단한 설명방법만 알려주자면, 준비물은 하나이다. 폰트파일.

 

 폰트파일의 데이터를 통째로 읽어 들이고, 크기를 알아야한다. 그것이 pFileView cjSize이다. pvResrved 시스템 예약으로 무조건 0(NULL)값을 줘야 하고, pNumFonts는 현재 폰트가 설치된 개수를 반환하는 포인터 값이다.

 

// v : 폰트 데이터를 담은 std::verctor

auto  date = reinterpret_cast<char*>(v.data());

auto  size = static_cast<DWORD>(v.size());

HANDLE out = AddFontMemResourceEx(data, size, 0, &nInstalled);

 

 이렇게 폰트를 설치하면 후는 자유롭게 사용이 가능하다.




문제는 DirectX 계열에서는 이렇게 해도 폰트를 찾지 못한다. 이 부분은 다음에 다루는 것으로.


[C++] 표준 라이브러리를 사용하여 숫자 세 자리마다 쉼표 붙이기 Lu's…〃 Programing。

  기능을 숫자 형식(numeric format)이라고 하겠다

 출처는 MSDN | https://msdn.microsoft.com/ko-kr/goglobal/bb688127.aspx

 

 매우 많은 목적으로, 숫자를 표기할 자리마다 쉼표를 붙인다. MSDN에서는 숫자 형식이라고 하던데, 표준 명칭인지는 모르겠다. 일단 문서는 해당 단어를 사용한다.

 

우선 숫자 형식에 대해 알아보자.

한국에서는 당연하게 정수부에 1000 단위로 쉼표를 붙이고 소수점을 표시하기 위해 정수부가 끝나고 마침표를 찍는다. 하지만 독일에서는 반대다! 1000 단위로 마침표를 찍고, 소수점을 표시하기 위해 쉼표를 찍는다.

 

 대체로 프로그래밍을 배우는 초기 단계에서 해당 기능을 구현해봤겠지만 이런 보편적인 기능은 왠지 표준에 있을 같다. 그런 생각을 하고 찾아보니 정말 있더라.

 

 

  

 국가나 문화에 따라 달라지는 것이 있다. 통화 단위, 시간 표시, 그리고 숫자 형식. 외에도 달라지는 것이 있을 있기 때문에 C++ 표준위원회에서는 std::locale이라는 클래스로 포맷들을 캡슐화 두었다. 포맷(통화 단위, 시간 표시, 숫자 형식) facet이라고 부른다. facet locale "설치"하는 식으로 사용할 있다.

 

 어떻게 설치하느냐, 그것은 정말로 간단하다.

 

    // 기본 로케일 생성

    std::locale loc"ko" };

    // facet 설치하여 새로운 로케일을 만든다.

    std::locale new_loclocnew std::num_put<char>{} };

 

  new_loc std::num_put<char> 설치한 로케일이다. 줄로 쓰기 위해 loc new_loc 안에서 생성해도 된다.

 

new_loc 사용하기 위해서는 std::streambuf 연결할 필요가 있다. 어떻게 하느냐, imbue 함수를 사용한다.


 예를 들어, std::cout 설치한다고 하면 코드는 다음과 같다.

 

    std::locale loc"ko" };
    std::locale new_loclocnew std::num_put<char>{} };
    std::cout.imbue(new_loc);

 

물론, 숫자 형식을 cout 말고 다른 곳에 쓰려는 사람이 많을 것이다. 경우에는 std::ostringstream 이용하자.

 

template<typename T>
std::
string ConvertNumericFormat(std::localelocT numeric)
{
    static_assert(std::is_arithmetic<T>::value, "numeric format is only number.");
 
    using stream_t = std::ostringstream;
    using iter_t = stream_t::_Iter;
 
    stream_t stream;
    stream.imbue(loc);


    std::use_facet<std::num_put<char>>(loc).put(iter_t(stream), stream' 'numeric);
    return stream.str();
}

 



 마지막으로, 성능은 책임지지 않는다. 국제화를 고려하지 않는 경우라면 숫자 형식을 구현하기에는 번잡스럽고 표준 함수로만 구현하고 싶은 경우에나 만하지, 실시간으로 점수가 갱신되어야 하는 게임 같은 곳에 사용하기에는 성능이 허용 가능한지 체크해보는 것이 좋을 것이다.


[WIN32] 멀티바이트가 아닌 인코딩된 문자열을 콘솔에 표시할 때 Lu's…〃 Programing。

최근, char*로 반환되는 문자열의 인코딩이 UTF-8인 경우를 맞딱뜨렸다. 이걸 UTF-8 인코딩 된 파일로 저장해서 읽으면 잘 읽어지는데 콘솔로 출력하니 인코딩이 깨지더라.

std::ios는 imbue라는 locale 설정 함수가 있다. 이를 상속받은 std::ostream, std::cout 등도 동일한 함수가 있고 이를 사용하면 ios에 들어간 데이터를 해당 로케일로 인코딩하여 보여준다. 그런데 이게 안 되더라!

  char* recv_msg; // char*로 반환된 UTF-8 문자

  std::cout.imbue(std::locale{ "ko_KR.UTF-8" }); // 한글 UTF-8 인코딩
  std::cout << recv_msg << std::endl;

이런 식으로 코딩하면 안 나온다!



 한참만에 이리 뒤지고 저리 굴러서 정답을 알아냈는데, 일단 어떻게 굴렀는지를 얘기해본다. 참고로 다 실패했다.

1. recv_msg를 wchar_t, char16_t, char32_t 등으로 형변환하여 읽어 봄
2. imbue 말고 setlocale 사용
3. codecvt_utf8 등을 이용하여 utf-8 문자로 강제 변환

이렇게 해도 안 되던 걸 어느 사이트에서 해답을 찾았는데, Win32 함수이다.

  SetConsoleOutputCP(CP_UTF8);

함수를 호출하니 잘 되더라. 이 함수는 Console Output의 코드페이지(CP)를 설정하는 함수인데, char*라지만 이미 UTF-8 인코딩이 된 문자열이었기 때문에 Console Output의 CP만 바꾸면 되지 않았나 싶다.

 정확히는 아직도 모르겠다. 정답을 아시는 분은 부디 댓글로 남겨주세요...

1 2 3 4 5 6 7 8 9 10 다음