2011-07-22 2 views
5

Я хотел бы получить движения мыши с высоким разрешением и высокой частотой кадров на OSX.Координаты с высоким разрешением и высокой частотой кадров на OSX? (Или другое решение?)

«Высокая частота кадров» = 60 кадров в секунду или выше (предпочтительно> 120)
«Высокое разрешение» значения = Subpixel

Проблема
У меня есть вид OPENGL работает на о частоте обновления монитора , поэтому ~ 60 кадров в секунду. Я использую мышь, чтобы осмотреться, поэтому я спрятал курсор мыши, и я полагаюсь на значения дельта мыши.

Проблема заключается в том, что события мыши происходят со слишком низкой частотой кадров, а значения привязаны к целому (целые пиксели). Это вызывает «прерывистый» просмотр. Вот визуализация значений мышей дельты с течением времени:

mouse delta X 
    ^    xx 
    2 |  x x x  x xx 
    | x x x x    xx x x x 
    0 |x-x-x--xx-x-x-xx--x-x----x-xx-x-----> frame 
    | 
-2 | 
    v 

Это типичный (укороченный) кривой, создаваемые от пользователя, перемещая мышь немного вправо. Каждое x представляет значение deltaX для каждого кадра, а так как значения deltaX округлены до целых чисел, этот график на самом деле довольно точен. Как мы видим, значение deltaX будет равно 0,000 на один кадр, а затем на 1.000 следующий, но затем он будет равен 0.000, а затем 2.000, а затем 0.000 снова, затем 3.000, 0.000 и т. Д.

Это означает, что вид повернет 2.000 единиц на один кадр, а затем повернет на 0,000 единиц дальше, а затем повернет 3.000 единиц. Это происходит, когда мышь перетаскивается с большей или меньшей постоянной скоростью. Невероятно сказать, это выглядит как дерьмо.

Итак, как я могу 1) увеличить частоту кадров мыши? и 2) получить субпиксельные значения?

До сих пор
Я попытался следующие:

- (void)mouseMoved:(NSEvent *)theEvent { 
    CGFloat dx, dy; 
    dx = [theEvent deltaX]; 
    dy = [theEvent deltaY]; 
    // ... 
    actOnMouse(dx,dy); 
} 

Ну, это один был очевиден. dx здесь float, но значения всегда округлены (0.000, 1.000 и т. Д.). Это создает график выше.

Итак, следующим шагом было попытаться нажать события мыши, прежде чем они войдут в WindowServer, подумал я. Таким образом, я создал CGEventTrap:

eventMask = (1 << kCGEventMouseMoved); 
eventTap = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 
      0, eventMask, myCGEventCallback, NULL); 
//... 
myCGEventCallback(...){ 
    double dx = CGEventGetDoubleValueField(event, kCGMouseEventDeltaX); 
    double dy = CGEventGetDoubleValueField(event, kCGMouseEventDeltaY); 
} 

Еще значения являются n.000, хотя я считаю, что скорость стрельбы события немного выше. Но это все равно не до 60 кадров в секунду. Я все еще получаю диаграмму выше.

Я также попытался установить чувствительность мыши очень высоко, а затем масштабировать значения на моей стороне. Но, похоже, OSX добавляет какое-то ускорение или что-то - значения становятся действительно «неустойчивыми» и, следовательно, непригодными для использования, а темп огня по-прежнему слишком низок.

Не повезло, я начал следить за событиями мыши по кроличьей дыре, и я приехал в IOKit. Это страшно для меня. Это безумный шотландец. Документация Apple становится странной и, кажется, говорит: «Если вы так глубоко, все, что вам действительно нужно, это файлы заголовков».

Так что я читал файлы заголовков. И я нашел несколько интересных лакомых кусочков.

В <IOKit/hidsystem/IOLLEvent.h> на линии 377 есть эта структура:

struct { /* For mouse-down and mouse-up events */ 
    UInt8 subx;  /* sub-pixel position for x */ 
    UInt8 suby;  /* sub-pixel position for y */ 
    // ... 
} mouse; 

Престол, это говорит позиция субпикселя! ОК. Затем по линии 73 в <IOKit/hidsystem/IOLLParameter.h>

#define kIOHIDPointerResolutionKey  "HIDPointerResolution" 

Хм.

В целом, я чувствую, что OSX знает о субпиксельных координатах мыши в глубине, и просто нужно читать способ чтения движений мыши в каждом кадре, но я просто не знаю, как получить эти значения.

Вопросы
Пуэр, так, что я прошу?

  • Есть ли способ получить события с высокой частотой кадров в OSX? (Пример кода?)
  • Есть ли способ получить координаты подпиксельной мыши в OSX? (Пример кода?)
  • Есть ли способ чтения «необработанных» мышей дельт в каждом кадре? (Ie не полагаться на событие.)
  • Или, как я могу получить NXEvents или установить HIDParameters? Пример кода? (Таким образом, я могу копать глубже в это сам ...)

(Извините за длинный пост)

ответ

1

Возможность координат субпикселей существует потому, что Mac OS X предназначен для разрешения независимой. Квадрат 2x2 аппаратных пикселей на экране может представлять собой один виртуальный пиксель в программном обеспечении, позволяющий размещать курсор на (x + 0.5, y + 0.5).

На любом фактическом Mac с использованием обычного масштабирования 1x вы никогда не увидите координаты подпикселя, так как курсор мыши не может быть перемещен на дробное положение пикселя на экране - квант движения мыши составляет ровно 1 пиксель.

1

Если вам нужно получить доступ к информации о треугольниках указателя устройства на более низком уровне, чем система диспетчеризации событий, то вам, вероятно, понадобится использовать user-space USB APIs.

1

Если вы используете обратные вызовы IOHIDDevice для мыши вы можете использовать это, чтобы получить двойное значение:

double doubleValue = IOHIDValueGetScaledValue(inIOHIDValueRef, kIOHIDTransactionDirectionTypeOutput); 
5

(Это очень поздно ответ, но один, что я думаю, что все еще полезно для других, наткнуться на это.)

Вы пробовали фильтровать ввод мыши? Это может быть сложно, потому что фильтрация, как правило, является компромиссом между запаздыванием и точностью. Однако несколько лет назад я написал статью, в которой объяснялось, как я отфильтровывал движения мыши и написал статью для сайта разработки игр. Ссылка: http://www.flipcode.com/archives/Smooth_Mouse_Filtering.shtml.

Поскольку этот сайт больше не находится под активным развитием (и может уйти) вот соответствующий отрывок:


Почти в каждом случае, фильтрация означает усреднение. Однако, если мы просто усредним движение мыши с течением времени, мы представим задержку.Как же мы фильтруем без каких-либо побочных эффектов? Ну, мы все равно будем использовать усреднение, но мы сделаем это с некоторым интеллектом. И в то же время мы дадим пользователю тонкий контроль над фильтрацией, чтобы они могли самостоятельно отрегулировать.

Мы будем использовать нелинейный фильтр усредненного ввода мыши с течением времени, где более старые значения оказывают меньшее влияние на результат фильтрации.

Как это работает

Каждый кадр, двигаться ли вы мышь или нет, мы помещаем текущее движение мыши в буфере истории и удалить самую старую историю. Таким образом, наша история всегда содержит X-образцы, где X - это «размер буфера истории», представляющий собой самые последние сэмплированные движения мыши с течением времени.

Если мы использовали размер буфера истории 10 и стандартное среднее для всего буфера, фильтр будет вводить много задержек. Быстрые движения мыши будут отставать от 1/6 секунды в машине 60FPS. В быстрой игре действие было бы очень плавным, но практически непригодным для использования. В том же сценарии размер буфера истории 2 был бы очень небольшим, но очень плохая фильтрация (грубые и отрывистые реакции игроков).

Нелинейный фильтр предназначен для борьбы с этим взаимоисключающим сценарием. Идея очень проста. Вместо того, чтобы просто вслепую усреднять все значения в буфере истории одинаково, мы усредняем их с весом. Начнем с веса 1.0. Таким образом, первое значение в буфере истории (текущий вход мыши текущего кадра) имеет полный вес. Затем мы умножаем этот вес на «модификатор веса» (скажем ... 0,2) и переходим к следующему значению в буфере истории. Чем дальше назад (через наш буфер истории) мы идем, значения имеют все меньший вес (влияние) на конечный результат.

Чтобы разработать с модификатором веса 0,5, образец текущего кадра будет иметь вес 100%, предыдущий образец будет иметь вес 50%, следующий самый старый образец будет иметь вес 25%, следующий будет иметь вес 12,5% и так далее. Если вы начертите это, это будет выглядеть как кривая. Таким образом, идея модификатора веса заключается в том, чтобы контролировать, насколько резко падает кривая, когда образцы в истории становятся старше.

Уменьшение задержки означает уменьшение модификатора веса. Уменьшение модификатора веса до 0 обеспечит пользователю необработанную, нефильтрованную обратную связь. Увеличение его до 1.0 приведет к тому, что результат будет простым средним из всех значений в буфере истории.

Мы предложим пользователю две переменные для точного управления: размер буфера истории и модификатор веса. Я имею тенденцию использовать размер буфера истории 10, и просто играю с модификатором веса, пока я не буду счастлив.

Смежные вопросы