【C++】MacPC環境で解像度の変更

2018年7月10日

個人的なメモとして、C++によるMac環境での解像度変更処理について書き記します。

解像度の変更は、CoreGraphicsAPIを使用した方法になります。API自体はC言語でもほぼ同じように扱えます。

※IDEはXcodeを使用する。

主に使用する関数、構造体とリンクが必要なライブラリ

CGMainDisplayID関数

メインディスプレイを示すIDを取得します。

メインディスプレイを操作する場合はこのIDと一緒に他の関数に引き渡すと良い。

戻り値はCGDirectDisplayID型

CGDisplayCopyDisplayMode関数

ディスプレイの現在の設定に関する情報を返します。

戻り値はCGDisplayModeRef型であり、解像度などの情報を保持している。

CGDisplayModeGetWidth関数

引数にはCGDisplayModeRefを引き渡し、横幅を取得する。

どうやらCGDisplayModeRef、もしくはCGDisplayModeから直接widthを取得できないみたいなので、この関数を経由する必要がある。

CGDisplayModeGetHeight関数

引数にはCGDisplayModeRefを引き渡し、縦幅を取得する。

CGDisplayModeGetRefreshRate関数

引数にはCGDisplayModeRefを引き渡し、リフレッシュレートを取得する。

CGDisplayCopyAllDisplayModes関数

指定したdisplayIdに設定可能なすべてのCGDisplayModeRefポインタを取得できます。

CGDisplaySetDisplayMode関数

指定したdisplayIdが示すディスプレイの解像度を指定したCGDisplayModeRefが示す解像度に変更します。


下記はリンクが必要なフレームワークです。CF系のAPIも使用するので、CoreFoundationもリンクが必要です。

CoreFoundation.framework

アプリケーションを作成する上であれば便利な基本関数群が使用できるようになります。

CoreGraphics.framework

Mac環境でグラフィック関連の処理を実装する際に便利な関数群が使用できるようになります。

フレームワークの追加は下記のサイトを参考にさせていただきました。
https://techacademy.jp/magazine/2703#sec1

現在の解像度設定情報を表示する

現在の解像度設定情報を取得するにはCGDisplayCopyDisplayModeを使用します。

引数には取得対象のディスプレイIDを引き渡します。

取得したポインタ使用してCGDisplayModeGet~関数を呼び出し各種値を取得します。

#include <iostream>
#include <CoreGraphics/CoreGraphics.h>

int main(int argc, const char * argv[]) {
    CGDirectDisplayID displayId = CGMainDisplayID();
    CGDisplayModeRef modePtr = CGDisplayCopyDisplayMode(displayId);
    std::string str = "";
    str += "横幅:"+std::to_string(CGDisplayModeGetWidth(modePtr)) ;
    str += ",縦幅:"+std::to_string(CGDisplayModeGetHeight(modePtr));
    str += ",リフレッシュレート:"+std::to_string(CGDisplayModeGetRefreshRate(modePtr));
    std::cout<<str<<std::endl;
    std::cout << "画面の解像度を取得したよ!" << std::endl;
    CGDisplayModeRelease(modePtr);
    return 0;
}

横幅:1920,縦幅:1080,リフレッシュレート:60.000000
画面の解像度を取得したよ!

設定可能な解像度を取得して情報表示する

CGDisplayCopyAllDisplayModesで設定可能なディスプレイモードをの配列を取得します。

引数には取得対象のディスプレイIDを引き渡します。

#include <iostream>
#include <CoreGraphics/CoreGraphics.h>

int main(int argc, const char * argv[]) {
    CGDirectDisplayID displayId = CGMainDisplayID();
    CFArrayRef arr = CGDisplayCopyAllDisplayModes(displayId, NULL);
    CFIndex len = CFArrayGetCount(arr);
    for ( int i = 0;i < len;i++ ) {
        CGDisplayModeRef modePtr = (CGDisplayModeRef)(CFArrayGetValueAtIndex(arr, i));
        std::string str = "";
        str += "横幅:"+std::to_string(CGDisplayModeGetWidth(modePtr)) ;
        str += ",縦幅:"+std::to_string(CGDisplayModeGetHeight(modePtr));
        str += ",リフレッシュレート:"+std::to_string(CGDisplayModeGetRefreshRate(modePtr));
        std::cout<<str<<std::endl;
    }
    
    CFRelease(arr);
    
    std::cout << "設定できる解像度を取得したよ!" << std::endl;
    return 0;
}
実行結果

横幅:1920,縦幅:1080,リフレッシュレート:60.000000
横幅:640,縦幅:480,リフレッシュレート:60.000000
横幅:720,縦幅:480,リフレッシュレート:60.000000
横幅:1280,縦幅:720,リフレッシュレート:60.000000
横幅:1920,縦幅:1080,リフレッシュレート:60.000000
横幅:720,縦幅:576,リフレッシュレート:50.000000
横幅:1280,縦幅:720,リフレッシュレート:50.000000
横幅:1920,縦幅:1080,リフレッシュレート:50.000000
横幅:1920,縦幅:1080,リフレッシュレート:50.000000
横幅:800,縦幅:600,リフレッシュレート:60.000000
横幅:1024,縦幅:768,リフレッシュレート:60.000000
横幅:1024,縦幅:576,リフレッシュレート:60.000000
横幅:1280,縦幅:960,リフレッシュレート:60.000000
横幅:1344,縦幅:1008,リフレッシュレート:60.000000
横幅:1344,縦幅:756,リフレッシュレート:60.000000
横幅:1600,縦幅:900,リフレッシュレート:60.000000
設定できる解像度を取得したよ!

解像度を変更する

CGDisplaySetDisplayModeでディスプレイIDとモードを引き渡して解像度を変更します。

下記は800×600の解像度に変更するサンプルです。5秒後にプログラムを終了し、元の解像度に戻るようになっています。

#include <iostream>
#include <CoreGraphics/CoreGraphics.h>

int main(int argc, const char * argv[]) {
    
    CGDirectDisplayID displayId = CGMainDisplayID();
    CFArrayRef arr = CGDisplayCopyAllDisplayModes(displayId, NULL);
    CFIndex len = CFArrayGetCount(arr);
    CGDisplayModeRef mode = nullptr;
    int ref = INT_MAX;
    for ( int i = 0;i < len;i++ ) {
        CGDisplayModeRef modePtr = (CGDisplayModeRef)(CFArrayGetValueAtIndex(arr, i));
        if ( CGDisplayModeGetWidth(modePtr) == 800 && CGDisplayModeGetHeight(modePtr) == 600 && abs(60 - (int)CGDisplayModeGetRefreshRate(modePtr)) < ref ) {
            ref = abs(60 - (int)CGDisplayModeGetRefreshRate(modePtr));
            mode = modePtr;
        }
    }
    CGDisplaySetDisplayMode(displayId, mode, nullptr);
    CFRelease(arr);
    
    //解像度の変更がわかるように5秒スリープ
    usleep(5*1000*1000);
    return 0;
}
実行結果(イメージ)

640×480に設定するとなぜかアスペクト比が維持されない・・・

C++

Posted by nompor