-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HidController: return QByteArrays for get[Input/Feature]Report #4521
Conversation
If we can't figure out how to make this work, I think we should merge #4520. |
I tried copying into the QByteArray with a loop instead of the QByteArray constructor but that didn't work either:
|
Were you able to replicate this in a standalone example? If so would you mind filing a bug on Qt Bugtracker? |
I did not make a minimal example to demonstrate this, but yes making a bug report upstream is a good idea. |
I wonder if the issue is that the QByteArray data is not kept alive long enough? https://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership
QByteArray does not inherit QObject. |
Shouldn't be the problem. Currently, the QByteArray is copying the input buffer. So The QByteArray owns the data for the rest of its lifetime. Since we're returning the QByteArray from the Q_INVOCABLE Method, the ownership should be transferred to JS. Maybe the automatic ownership change is broken in Qt? |
This is definitely not an ownership issue but maybe a type mapping issue? As Jan pointed out the I consider it very unlikely that passing of |
Oh, I understand the issue now. getInputReport returns a QByteArray which does get converted to a JavaScript ArrayBuffer, but ControllerScriptEngineLegacy has a hack for backwards compatibility to transform the ArrayBuffer to a Uint8Array, which requires a QJSEngine... https://github.com/mixxxdj/mixxx/blob/main/src/controllers/scripting/legacy/controllerscriptenginelegacy.cpp#L98 |
This still requires two layers of boilerplate:
instead of the current situation with
I think this is still a good improvement over the current situation even if there is some boilerplate required. |
I do not consider that code boilerplate really, but exposing a buffer as an ArrayBuffer instead of an array of ints is definitely an improvement. |
So to reiterate, the code itself works right? We just get an |
Yes. |
@JoergAtGithub what do you think about this? |
for compatibility with HidController::poll
297113b
to
7e450c6
Compare
Great, that is much better than an Uibt8Array, because you can use the DataView API with multi byte int/float support, etc.: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView |
I'm trying to get it work, but struggle a bit: 2.) HIDDebug seems to be incompatible to this type: 3.) For all bitwise ( 4.) The function sendFeatureReport has still QList as argument and no longer matchs to the output of getFeatureReport. The typical use case is for feature reports is to set or unset a single configuration bit, which worked with QList as following:
But this is a solution I can use. For me it's less comfortable, but if it helps other, I would be fine with this. |
} | ||
return dataList; | ||
return QByteArray::fromRawData( | ||
reinterpret_cast<char*>(m_pPollData[m_pollingBufferIndex]), bytesRead); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reintepret_casts are more dangerous than static_casts.
would this also work?
reinterpret_cast<char*>(m_pPollData[m_pollingBufferIndex]), bytesRead); | |
static_cast<char*>(m_pPollData[m_pollingBufferIndex]), bytesRead); |
or maybe
reinterpret_cast<char*>(m_pPollData[m_pollingBufferIndex]), bytesRead); | |
static_cast<char*>(&m_pPollData[m_pollingBufferIndex]), bytesRead); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, with the first:
/home/be/sw/mixxx/src/controllers/hid/hidcontroller.cpp: In member function ‘QByteArray HidController::getInputReport(unsigned int)’:
/home/be/sw/mixxx/src/controllers/hid/hidcontroller.cpp:192:13: error: invalid ‘static_cast’ from type ‘unsigned char [255]’ to type ‘char*’
192 | static_cast<char*>(m_pPollData[m_pollingBufferIndex]), bytesRead);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
with the second:
/home/be/sw/mixxx/src/controllers/hid/hidcontroller.cpp: In member function ‘QByteArray HidController::getInputReport(unsigned int)’:
/home/be/sw/mixxx/src/controllers/hid/hidcontroller.cpp:192:13: error: invalid ‘static_cast’ from type ‘unsigned char (*)[255]’ to type ‘char’
192 | static_cast<char>(&m_pPollData[m_pollingBufferIndex]), bytesRead);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I looked into the issue. The problem is not the array cast, its the unsigned-to-signed conversion.
https://godbolt.org/z/n974WvWz9
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the reinterpret cast is unavoidable as far as I can tell.
That is annoying.
Thank you for pointing this out. I pushed a commit to fix this and make sendFeatureReport take a QByteArray. So your JS example would be:
Alternatively you could use a DataView without creating a Uint8Array. |
@JoergAtGithub does the new API work for you now that |
For me personally this works, I could fullfill all my use cases with this too. |
It is very subjective whether a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@JoergAtGithub are you fine with the proposed API changes?
I've no strong opinion here. I found the data list easier to use in the mapping, but if you see benefits in ArrayBuffer, than merge this! |
Great, thank you very much. Do you know what mappings are affected by this API change? Would you volunteer to fix them? |
I think only my Z2 mapping, and BEs S4 mapping are affected |
-Now the arguments are identical with the similar function getFeatureReport -This array is no longer compatible with incomingData anyway, because the type changed in mixxxdj#4521 -And even before, it was only compatible, under the assumption, that the HID device uses ReportIds Note, that getInputReport is new for 2.4 and can be changed without breaking backward compatibility
for compatibility with HidController::poll
Currently, passing the QList return value to the script's
incomingData
function requires usingUint8Array.from
.Unfortunately this is not working. Garbage data is returned to JavaScript. I do not understand why this does not work but #4520 does. Maybe it is the call to QJSEngine::toScriptValue that does the trick? But I thought Qt did that automatically... suggestions??