Различные форматы курсора в IOFrameBufferShared - PullRequest
3 голосов
/ 12 марта 2010

Я читаю данные растрового изображения самого курсора из структуры StdFBShmem_t, как определено в IOFrameBufferShared API .

Все отлично работает, 90% времени. Тем не менее, я заметил, что некоторые приложения на Mac устанавливают курсор в другом формате. Согласно документации для структур данных, формат растрового изображения курсора всегда должен быть в том же формате, что и буфер кадра. Мой кадровый буфер - 32 bpp . Я ожидаю, что данные растрового изображения будут в формате 0xAARRGGBB, который это (в большинстве случаев). Однако в некоторых случаях я читаю данные, которые выглядят как маска. В частности, пиксели в этих данных будут либо 0x00FFFFFF, либо `0x00000000. Мне кажется, это маска для отдельных данных пикселей, хранящихся где-то еще.

Насколько я могу судить, единственное приложение, которое использует этот пиксельный формат курсора, это Qt Creator , но мне нужно работать со всеми приложениями, поэтому я бы хотел разобраться с этим. *

Код, который я использую для чтения данных растрового изображения курсора:

NSAutoreleasePool *autoReleasePool = [[NSAutoreleasePool alloc] init];

NSPoint mouseLocation = [NSEvent mouseLocation];
NSArray *allScreens = [NSScreen screens];
NSEnumerator *screensEnum = [allScreens objectEnumerator];
NSScreen *screen;
NSDictionary *screenDesc = nil;
while ((screen = [screensEnum nextObject]))
{
    NSRect screenFrame = [screen frame];
    screenDesc = [screen deviceDescription];
    if (NSMouseInRect(mouseLocation, screenFrame, NO))
        break;
}

if (screen)
{
    kern_return_t err;

    CGDirectDisplayID displayID = (CGDirectDisplayID) [[screenDesc objectForKey:@"NSScreenNumber"] pointerValue];
    task_port_t taskPort = mach_task_self();
    io_service_t displayServicePort = CGDisplayIOServicePort(displayID);
    io_connect_t displayConnection =0;
    err = IOFramebufferOpen(displayServicePort,
                            taskPort,
                            kIOFBSharedConnectType,
                            &displayConnection);
    if (KERN_SUCCESS == err)
    {
        union
        {
            vm_address_t vm_ptr;
            StdFBShmem_t *fbshmem;
        } cursorInfo;
        vm_size_t size;

        err = IOConnectMapMemory(displayConnection,
                                 kIOFBCursorMemory,
                                 taskPort,
                                 &cursorInfo.vm_ptr,
                                 &size,
                                 kIOMapAnywhere | kIOMapDefaultCache | kIOMapReadOnly);
        if (KERN_SUCCESS == err)
        {
            // For some reason, cursor data is not always in the same format as
            // the frame buffer. For this reason, we need some way to detect
            // which structure we should be reading.
            QByteArray pixData(
              (const char*)cursorInfo.fbshmem->cursor.rgb24.image[currentFrame],
              m_mouseInfo.currentSize.width() * m_mouseInfo.currentSize.height() * 4);

            IOConnectUnmapMemory(displayConnection,
                                 kIOFBCursorMemory,
                                 taskPort,
                                 cursorInfo.vm_ptr);
        } // IOConnectMapMemory
        else
            qDebug() << "IOConnectMapMemory Failed:" << err;
        IOServiceClose(displayConnection);
    } // IOServiceOpen
    else
        qDebug() << "IOFramebufferOpen Failed:" << err;
}// if screen
[autoReleasePool release];

Мои вопросы:

  1. Как определить, что курсор находится в другом формате? из кадрового буфера?

  2. Где я могу прочитать фактические данные пикселей? bm18Cursor Структура содержит раздел маски, но это не в правильное место для меня, чтобы читать его с помощью кода выше.

Ответы [ 2 ]

2 голосов
/ 15 марта 2010

Вы можете попробовать функцию CGSCreateRegisteredCursorImage, как продемонстрировал Карстен в комментарии к моему блогу .

Это частная функция, поэтому она может измениться или исчезнуть в любое время, поэтому вам следует проверить, существует ли она, и сохранить IOFramebuffer в резерве, но пока она существует, вы можете найти ее более надежной, чем комплексная. и тонко документированный IOFramebuffer.

2 голосов
/ 14 марта 2010

Как определить, что курсор отличается от фреймбуфера?

Курсор находится в буфере кадров. Он не может быть в другом формате, чем он сам.

Невозможно определить, в каком формате он находится (x-radar: // problem / 7751503). Был бы способ угадать, по крайней мере, количество байтов на пиксель, если бы вы могли сказать, сколько кадров имеет курсор, но так как вы не можете (эта информация не установлена ​​по состоянию на 10.6.1 - x-radar: / / problem / 7751530), вам остается попытаться определить два фактора четырехфакторного произведения (байт на пиксель × ширина × высота × количество кадров, где у вас есть только ширина, высота и произведение). И даже если вы сможете выяснить эти недостающие два фактора, вы все равно не будете знать, в каком порядке расположены байты или предварительно умножены компоненты цвета альфа-компонентом.

Где я могу прочитать фактические данные о пикселях?

В элементе cursor структуры общей памяти курсора.

Вы должны определить IOFB_ARBITRARY_SIZE_CURSOR перед включением заголовков I / O Kit. Курсоры могут быть любого размера, а не только 16 × 16, то есть того размера, который вы ожидаете, когда не определяете эту константу. Например, обычный курсор стрелки Mac - 24 × 24, курсор стрелки «Windows» в CrossOver - 32 × 32, а курсор стрелки в X11 - 10 × 16.

Однако в некоторых случаях я читаю данные, похожие на маску. В частности, пиксели в этих данных будут либо 0x00FFFFFF, либо 0x00000000. Мне кажется, это маска для отдельных данных пикселей, хранящихся где-то еще.

Для меня это больше похоже на 16-битные пиксели с 8-битным альфа-каналом. По крайней мере, это скорее 5-6-5, чем 5-5-5.

Насколько я могу судить, единственное приложение, которое использует этот пиксельный формат курсора, это Qt Creator, но мне нужно работать со всеми приложениями, поэтому я бы хотел разобраться с этим.

Я могу захватить текущий курсор в этом приложении, с помощью моего нового приложения для захвата курсора . Есть ли какая-то конкретная часть приложения, которую я должен нажать, чтобы он показывал мне определенный курсор?

...