LINUX.ORG.RU

XGetDeviceProperty для «Evdev Axis Calibration» возвращает четыре нуля

 


0

1

Есть необходимость получения информации о калибровке сенсорного экрана. Ну я запрашиваю через XGetDeviceProperty информацию для атома «Evdev Axis Calibration», а он мне возвращает 4 числа, равных 0 (как если запускать код под обычным пользователем, так и под root). Если заглянуть в «man evdev», то там пишется следующее.

man evdev

Evdev Axis Calibration 4 32-bit values, order min-x, max-x, min-y, max-y or 0 values to disable in-driver axis calibration.

Т.е. эти четыре нуля вроде бы корректные значения, но когда вызываю команду

«xinput list-props <имя моего устройства сенсорного экрана а ля 'HID 1234:5678'>»

то выводит ненулевую информацию (понятно что некалиброванную).

xinput list-props

Evdev Axis Calibration (258): 0, 0, 32985328, 49

Мне непонятно несоответствие полученной информации из libX11 (libXi) и через «xinput list-props».

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

Ну, покажи тогда код. Как получаешь идентификатор для XOpenDevice? Это точно то устройство открывается или нет?

Zubok ★★★★★
()

Рекомендую скачать исходник xinput_calbrator. Там должно все быть. Утилитка как раз вокруг этой темы. Там и подсмотришь.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Получение «Display».

int a, b, c;
if (0 == XQueryExtension(m_pXDisplay, "XInputExtension", &a, &b, &c))
{
    return <ошибка>;
}

Код перебора устройств по классам-валюаторам приводить не буду, т.к. он некороткий, и я неоднократно убедился, что он работает. Имя устройства находится нормально, и xinput его понимает. Из него получаю XID сенсорного экрана.

А потом получаю «устройство».

m_pXDevice = XOpenDevice(m_pXDisplay, m_vecTouchInfo[m_uInfoIdx].m_XID);
if (0 == m_pXDevice)
{
    XCloseDisplay(m_pXDisplay);
    m_pXDisplay = 0;
    return <ошибка>;
}

Тут едва ли ошибки.

Я выяснил, почему нули мне возвращает. У меня в коде проблемы с записью настроек калибровки через XChangeDeviceProperty.

После того, как evdev-у отправляю неадекватные значения он их не сохраняет, а в ответ шлет нули (видимо сообщает, что дальше калибровать нельзя). Спасает перезагрузка Linux-а. После перезагрузки xinput говорит, что устройство вообще без данных калибровки, и можно задавать свои значения.

За совет с xinput_calibrator спасибо. Запускал, но исходники пока не смотрел. Вот теперь посмотрю.

dmitryshm
() автор топика
Ответ на: комментарий от Zubok

Про получение Display перепутал. Вот код.

m_pXDisplay = XOpenDisplay("");
if (0 == m_pXDisplay)
{
    return <ошибка>;
}

Но это едва ли что-то изменит.

Проблема сейчас вот здесь, пока не пойму, почему именно, но факт в том, что после его отработки в «Evdev Axis Calibration» содержится ерунда.

const uint32_t arrCalibData[4] = {refData_.m_iMinX, refData_.m_iMaxX, refData_.m_iMinY, refData_.m_iMaxY};
if ((0 == m_pXDisplay) || (0 == m_pXDevice))
{
    return <ошибка>;
}
::Atom atomProp = XInternAtom(m_pXDisplay, "Evdev Axis Calibration", 0);
XChangeDeviceProperty(m_pXDisplay, m_pXDevice, atomProp, XA_INTEGER, sizeof(uint32_t)*8, PropModeReplace, reinterpret_cast<const unsigned char*>(arrCalibData), sizeof(arrCalibData)/sizeof(arrCalibData[0]));
XSync(m_pXDisplay, 0);
Перепутываются порядок первых двух значений, а последние 2 из 4 вообще отрицательные записываются, когда отправляются положительные. Будто с размером перепутал что-то. Но приведенный код, кажется, все по докам делает, и размеры правильные.

dmitryshm
() автор топика
Ответ на: комментарий от Zubok

Сделал как в xinput_calibrator, работал не через int, а через long. Заработало. Читает правильно, пишет свойства правильно. Остается вопрос. Почему работает, ведь в документации ясно пишется, что данные для XA_INTEGER при формате 32 это 32-битные данные, и работать он должен с int. Ан нет, надо long.

man XChangeDeviceProperty

format

Specifies whether the data should be viewed as a list of 8-bit, 16-bit, or 32-bit quantities. Possible values are 8, 16, and 32. This information allows the X server to correctly perform byte-swap operations as necessary. If the format is 16-bit or 32-bit, you must explicitly cast the data pointer to an (unsigned char*) in the call to XChangeDeviceProperty.

dmitryshm
() автор топика
Ответ на: комментарий от dmitryshm

для XA_INTEGER при формате 32 это 32-битные данные, и работать он должен с int. Ан нет, надо long.

С какой-то стати он должен с int? XA_INTEGER - это просто значит, что данные - целое число, а 32 бита не смущает? Не гарантируется 32 бита через int.

int - basic signed integer type. At least 16 bits in size.

long - long signed integer type. At least 32 bits in size.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Я использовал uint32_t, не утверждал, что int это всегда 32 бита. В моей системе с LP64 ABI int 32-разрядный. Ты очень редко встретишь систему с ILP64 ABI, только если специально ядро соберешь так для себя.

Так или иначе найдено вранье в man-страницах про libX11. С 32-разрядными величинами вызовы не работают на 64-разрядной системе с LP64 ABI. Работают с 64-разрядными данными, что противоречит докам. Там должен быть описан формат 64 вместо 32.

dmitryshm
() автор топика
Ответ на: комментарий от dmitryshm

А, у тебя 64-бита. Полагаю, что дело в выравнивании тут (alignment):

uint32_t arrCalibData[4] = {refData_.m_iMinX, refData_.m_iMaxX, refData_.m_iMinY, refData_.m_iMaxY};

Я полагаю, что у тебя выравнивание по границе 8 байт между членами массива. Проверь-ка. В man ошибки нет.

Я использовал uint32_t, не утверждал, что int это всегда 32 бита

Ну, ты произнес int в прошлом посте.

Zubok ★★★★★
()
Ответ на: комментарий от Zubok

Проверял, та же ошибка при использовании памяти из кучи. Я описал, в чем ошибка в man. Если бы все было так, как описано в man, то работал бы формат 32. Пришлось же воспользоваться форматом 64 на 64-разрядной системе.

dmitryshm
() автор топика
Ответ на: комментарий от dmitryshm

Проверял, та же ошибка при использовании памяти из кучи. Я описал, в чем ошибка в man. Если бы все было так, как описано в man, то работал бы формат 32. Пришлось же воспользоваться форматом 64 на 64-разрядной системе.

А я посмотрел исходники этой функции. Они в случае, когда format равен 32, рассматривают данные как long на любой архитектуре.

XChangeDeviceProperty(Display* dpy, XDevice* dev,
                      Atom property, Atom type,
                      int format, int mode,
                      _Xconst unsigned char *data, int nelements)
{
    xChangeDevicePropertyReq   *req;
    int                         len;

    XExtDisplayInfo *info = XInput_find_display(dpy);

    LockDisplay(dpy);
    if (_XiCheckExtInit(dpy, XInput_Initial_Release, info) == -1)
	return;

    GetReq(ChangeDeviceProperty, req);
    req->reqType    = info->codes->major_opcode;
    req->ReqType    = X_ChangeDeviceProperty;
    req->deviceid   = dev->device_id;
    req->property   = property;
    req->type       = type;
    req->mode       = mode;
    if (nelements < 0) {
	req->nUnits = 0;
	req->format = 0; /* ask for garbage, get garbage */
    } else {
	req->nUnits = nelements;
	req->format = format;
    }

    switch (req->format) {
    case 8:
	len = ((long)nelements + 3) >> 2;
	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
	    SetReqLen(req, len, len);
	    Data (dpy, (char *)data, nelements);
	} /* else force BadLength */
	break;

    case 16:
	len = ((long)nelements + 1) >> 1;
	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
	    SetReqLen(req, len, len);
	    len = (long)nelements << 1;
	    Data16 (dpy, (short *) data, len);
	} /* else force BadLength */
	break;

    case 32:
	len = nelements;
	if (dpy->bigreq_size || req->length + len <= (unsigned) 65535) {
	    SetReqLen(req, len, len);
	    len = (long)nelements << 2;
	    Data32 (dpy, (long *) data, len);
                         ^^^^^^^^
	} /* else force BadLength */
	break;

    default:
	/* BadValue will be generated */ ;
    }

    UnlockDisplay(dpy);
    SyncHandle();
}
Zubok ★★★★★
()
Ответ на: комментарий от dmitryshm

man XChangeDeviceProperty

И, кстати, в man как раз все написано, но только не про XChangeDeviceProperty, а про XGetDeviceProperty (но страничка одна и та же):

prop_return Returns the data in the specified format. If the returned format is 8, the returned data is represented as a char array. If the returned format is 16, the returned data is represented as an array of short int type and should be cast to that type to obtain the elements. If the returned format is 32, the property data will be stored as an array of longs (which in a 64-bit application will be 64-bit values that are padded in the upper 4 bytes).

При получении считается, что получишь long. Значит, вероятно, и при записи ждет long, но в этом же man об этом не упоминается.

Zubok ★★★★★
()
Последнее исправление: Zubok (всего исправлений: 1)
Ответ на: комментарий от Zubok

спасибо

О, вот оно что. Большое спасибо, что помог разобраться до конца!

dmitryshm
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.