4

我正在从IOFrameBufferShared APIStdFBShmem_t中定义的结构中读取最重要的光标像素图数据。

一切正常,90% 的时间。但是,我注意到 Mac 上的某些应用程序以不同的格式设置光标。根据数据结构的文档,光标像素图格式应始终与帧缓冲区的格式相同。我的帧缓冲区是 32 bpp。我希望像素图数据的格式0xAARRGGBB为(大多数情况下)。但是,在某些情况下,我正在读取看起来像掩码的数据。具体来说,此数据中的像素将是0x00FFFFFF0x00000000 或 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 结构包含一个掩码部分,但它不适合我使用上面的代码阅读它。

4

2 回答 2

2

如何检测光标是否与帧缓冲区的格式不同?

光标位于帧缓冲区中。它不能采用与自身不同的格式。

没有办法知道它是什么格式(x-radar://problem/7751503)。如果您可以知道光标有多少帧,那么至少有一种方法可以预测每个像素的字节数,但是因为您不能(该信息未设置为 10.6.1 — x-radar:/ /problem/7751530),您只能尝试找出四因子乘积的两个因子(每像素字节数 × 宽度 × 高度 × 帧数,其中只有宽度、高度和乘积)。即使你能弄清楚这两个缺失的因素,你仍然不知道字节的顺序或者颜色分量是否被 alpha 分量预乘。

我在哪里可以读取实际的像素数据?

cursor共享游标内存结构的成员中。

您应该IOFB_ARBITRARY_SIZE_CURSOR在包含 I/O Kit 标头之前进行定义。游标现在可以是任何大小,而不仅仅是 16×16,这是您在未定义该常量时所期望的大小。例如,通常的 Mac 箭头光标为 24×24,CrossOver 中的“Windows”箭头光标为 32×32,X11 中的箭头光标为 10×16。

但是,在某些情况下,我正在读取看起来像掩码的数据。具体来说,此数据中的像素将是0x00FFFFFF0x00000000。这在我看来是存储在其他地方的单独像素数据的掩码。

这听起来更像是带有 8 位 Alpha 通道的 16 位像素。至少它比 5-5-5 更可能是 5-6-5。

据我所知,唯一使用这种光标像素格式的应用程序是 Qt Creator,但我需要使用所有应用程序,所以我想解决这个问题。

我可以使用我的新光标捕获应用程序来捕获该应用程序中的当前光标。我应该点击应用程序的特定部分以使其显示特定光标吗?

于 2010-03-13T22:27:30.453 回答
2

您可以尝试 CGSCreateRegisteredCursorImage 函数,正如Karsten 在我的博客上的评论中所展示的那样

它是一个私有函数,所以它可能随时改变或消失,所以你应该检查它是否存在并保留IOFramebuffer,但只要它存在,你可能会发现它比复杂和薄的更可靠-记录的 IOFramebuffer。

于 2010-03-15T08:47:46.237 回答