LVN_ITEMCHANGING - Distinguish user input - c++

I'm handling the LVN_ITEMCHANGING message, but it gets signaled every time the check state is changed.
I need a way to distinguish between the user changing the check state, and me calling ListView_SetCheckState
Is there any easy way to do this? A different message I don't know about maybe? Or does anyone have any suggestions?

ListView_SetCheckState sends the LVM_SETITEMSTATE message. LVN_ITEMCHANGING message is also sent to the control's parent window. This means, the function is synchronous, and LVN_ITEMCHANGING handler is executed before ListView_SetCheckState call returns. This allows to use simple boolean flag, like:
bChangedByProgram = TRUE;
ListView_SetCheckState(...);
bChangedByProgram = FALSE;
In LVN_ITEMCHANGING handler:
if ( ! bChangedByProgram )
{
// item state is changed by user
}

Related

validating UpdateData(true) return value in MFC OnTimer routine

I am working on an MFC application(VS2017).
In that I have a made one second timer. Inside the OnTimer() routine along with my business logic I am calling UpdateData(FALSE) to show some runtime info back to UI.
Also, I have to get some user input from the UI for that inside the user Input Event handler, I am calling UpdateData(TRUE) and checking its return value in OnTimer routine.
Problem is since the timer is an independent entity here. Even though I have guarded the UpdateData(FALSE) inside OnTimer the UpdateData(FALSE) is getting executed for a blank user input, which crashes the program by calling assert.
/***SAMPLE Problem CODE****/`
void abc::OnEnUserInput()
{
IsvalidInput = UpdateData(TRUE);
}
void abc::OnTimer(UINT_PTR nIDEvent)
{
if (IsvalidInput == true)
{
UpdateData(FALSE);
}
}
Any help would be greatly appreciated!!!
Thanks.
Got my solution earlier itself but due to the busy schedule couldn't get time to share it.
for avoiding this issue I opened another dialogue box to receive the user input, since UpdatedData(FALSE) in OnTimer() is in background dialogue box so the user input in child dialog UpdateData(TRUE) will not interfare with background UpdatedData(FALSE).

Callback of request is never called when I put std::this_thread::sleep_for(1)

I am trying to prevent entering in scene if some stuff from server are not loaded, I have flag bool
done = false;
CCHttpRequest *pRequest;
// initialization ....
pRequest->setResponseCallback(this, httpresponse_selector(SceneController::on_response));
CCHttpClient::getInstance()->send(pRequest);
pRequest->release();
while(!done) {
std::chrono::milliseconds duration(1);
std::this_thread::sleep_for(duration);
}
in function callback on_response I set
done = true;
what should ( but doesn't work ) break out of infinite loop.
Problem with this approach is that callback is never called ( breakpoint at the first line in callback is never reached ). When I comment while loop it called callback.
Does anyone know what is a problem and how to prevent further execution until I fetch data from server ?
Callstack when it works on break point inside callback
Callback is NOT another thread as you might be thinking. You trying hold current function execution 'till callback gets called'. That's not correct. You should return from it and allow callback to be called. This should do:
done = false;
CCHttpRequest *pRequest;
// initialization ....
pRequest->setResponseCallback(this, httpresponse_selector(SceneController::on_response));
CCHttpClient::getInstance()->send(pRequest);
pRequest->release();
if (!done)
{
return;
}
else
{
// Do here whatever you want to do after callback changes flag
}
All your code would be executed in Cocos thread, CCHttpRequest has its own thread to fetch data from server then when all data was fetched the callback you registered before would be called in cocos thread, too.
After the registration of callback, cocos thread continues to execute to your while, now the callback is not called (data isn't completed) your while will run forever. When the data is completed, callback need to be executed in cocos thread but you're seeing the while keep blocking it.
In async world (see here, and here, you must understand async), you cannot "prevent further execution until you fetch data from server" with the pattern you are using. Try to prevent it by your done variable in places that you want it does not be executed.
E.g:
done = false;
CCHttpRequest *pRequest;
// initialization ....
pRequest->setResponseCallback(this, httpresponse_selector(SceneController::on_response));
CCHttpClient::getInstance()->send(pRequest);
pRequest->release();
and then in any you don't want user to interact with your game interface, as in Touch:
void onTouchBegan(Event *pEvent, Touch *pTouch)
{
if (!done)
{
return false;
}
// code when `done == true`
}
void onTouchEnded(Event *pEvent, Touch *pTouch)
{
// Code here will not be executed if `onTouchBegan` return `false`
}
whenever onTouchBegan return false, no more of touch code will be executed then prevent your user from interacting with game's element.
Also to prevent buttons menu clicking, set disable to their parent Menu container: menu->setEnabled(false) then set back to enabled when fetching done.

How to override keyPressEvent of QTextEdit?

I override keyPressEven() of widget QTextEdit:
void myTextEdit::keyPressEvent(QKeyEvent *e)
{
if(e->key()==Qt::Key_0)
{
qDebug() << "Ok";
}
}
Button 0 works - show "Ok", but does not write in field of QTextEdit. Why? Thanks advance.
You need to call the base class implementation if you want to keep the default behaviour:
void myTextEdit::keyPressEvent(QKeyEvent *e)
{
if(e->key()==Qt::Key_0)
{
qDebug() << "Ok";
}
QTextEdit::keyPressEvent(e);
}
See the docs for keyPressEvent.
In case someone using PySide2 is having trouble overriding QTextEdit's built-in keybindings, I post my solution here. Hopefully this is also useful for C++.
Scenario:
We are using a QTextEdit in an application and want to distribute a series of keybindings, but the text editor has already several hardcoded bindings. We want the editor to ignore them and hand them over to its parent, so they can be eventually handled by our code.
Problem:
While the docs say that whenever an event is ignored (e.g. by returning True in the installed eventFilter method) it automatically gets passed on to the parent, the truth is that when doing that for predefined keybindings QTextEdit did not hand them over: the event got ignored AND absorbed. So any textedit built-in keybindings filtered this way will be effectively globally disabled.
Direct event passing via sendEvent inside the editor's eventFilter had an interesting effect:
When calling sendEvent and returning super().sendEvent, the keybinding got executed by the editor AND the event passed to the receiver.
When calling sendEvent and returning True, the keybinding didn't get executed, and the event didn't get passed to the receiver.
When calling sendEvent and returning False, the keybinding didn't get executed, and the event passed to the receiver twice.
Furthermore:
Using event.ignore() didn't have any effect: the editor executed the built-in anyway.
Trying to discriminate via event.spontaneous() caused a segfault due to a missing pointer. Probably something got GCed but didn't try to debug that.
Trying to replace the event with a "dummy event" and call super also didn't work. Magically, the text editor kept executing the built-ins.
Maybe I missed something. Anyway, below I detail the approach that worked for me.
Solution:
The plan is to completely block the event, but broadcast it via signals, and then connect to them wherever we want. In your text editor instance, define the signal e.g. as follows:
eventCatched = QtCore.Signal(QtCore.QEvent)
Then, e.g. the following event filter will prevent execution of a few keybindings, and emit them once via eventCatched:
def eventFilter(self, obj, evt):
"""
Remember to install via self.installEventFilter(self)
"""
catch_control_keys = {QtCore.Qt.Key_Left, QtCore.Qt.Key_Right}
catch = False
# documentation for keys and modifiers:
# https://doc.qt.io/qtforpython-5/PySide2/QtCore/Qt.html
if evt.type() == QtCore.QEvent.KeyPress:
modifiers = evt.modifiers()
ctrl = bool(modifiers & QtCore.Qt.ControlModifier)
shift = bool(modifiers & QtCore.Qt.ShiftModifier)
alt = bool(modifiers & QtCore.Qt.AltModifier)
key = evt.key()
# catch all undo/redo builtins
if ((ctrl and shift and key == QtCore.Qt.Key_Z) or
evt.matches(QtGui.QKeySequence.Undo) or
evt.matches(QtGui.QKeySequence.Redo)):
catch = True
# catch specified control-keys
if ctrl and not shift and not alt:
if key in catch_control_keys:
catch = True
#
if catch:
# block event but send it as signal
self.eventCatched.emit(evt)
return True
else:
return super().eventFilter(obj, evt)
Then, we are free to connect the signal wherever we want to, we just need a method that handles events. In my case, I just wanted to pass them to the main window, which can be done with the following one-liner in the constructor:
text_editor.eventCatched.connect(lambda evt: QtCore.QCoreApplication.sendEvent(self, evt))
This way, whenever we catch an event in the text editor, it will be ignored and won't be propagated the standard way. Instead, a signal will be emitted, and we can subscribe to that signal to e.g. restart the propagation tree at a different point, as shown here via sendEvent.
Hope this helps!
Cheers,
Andres

C++ WM_KEYDOWN different intervals

I am currently trying to get KeyBoard Input from the WM_KEYDOWN and WM_CHAR message for my own InputBox.
This is the code that I am using for basic input, which works fine for characters:
if(msg.message == WM_KEYDOWN)
{
keyHandled = false;
//handle other keys here, e.g. VK_LEFT
}
else if(msg.message == WM_CHAR && !keyHandled)
{
keyHandled = true;
gui->UpdateInput(msg.wParam);
}
If the key that is being pressed is also a key that triggers the WM_CHAR message, the interval is as in usual input boxes.
However, if it is a key like VK_LEFT, it keeps receiving the WM_KEYDOWN message without any delay.
Is there any way that I can receive all keys with the same interval or do I have to implement a timer that handles the delay between the messages? I have also had a look at the WM_KEYDOWN message on msdn, but I could not find anything related to the intervals.
Windows has its own delays for sending Keyboard events from Keyboard input and this isn't something you can simply change. As you know, holding down a key will result in a first message, a delay, and then a series of more messages with a quicker interval. You can get around this by requesting states rather than relying on the messages directly. This is called Unbuffered input and is state oriented. To store your states, you can do the following:
bool keys[256];
When you are checking windows events, you can update the key states accordingly like this:
//In your WinProc function most likely
if (msg.message == WM_KEYDOWN)
{
keys[msg.wParam] = true;
}
if (msg.message == WM_KEYUP)
{
keys[msg.wParam] = false;
}
Then whenever you'd like, you can request the state of a specific key through the following function:
bool getKeyPressed(char keycode)
{
return keys[keycode];
}
For example:
//This could be in some random update function and called
//whenever you need the information.
if (getKeyPressed(VK_UP))
{
//Do something here...
}
The above function can be used wherever you'd like, therefore the frequency at which you update is completely up to you at that point. As mentioned before, this is Unbuffered input and is State oriented, whereas Buffered Input is Event oriented.
I think that this internal delay can not be modified easily.
One approach could be writing your own general key handler that keeps track of the states of all keys. For example, a list containg the keycodes of all pressed keys. On WM_KEYDOWN you add the keycode to the list and on WM_KEYUP you remove it. Then create something like a timer that simply notifies you in the desired delay times and calls your key handling function for each element of the list.

Keypress event in C++

I'm currently using GetAsyncKeyState() to detect Keydown events, but then the events will be repeated while you are holding down the key.
What would be an easy way to stop the event from repeating?
Example
If I hold down the key i on my keyboard for a while, I will get an output like this:
iiiiiiiiiiiiiiiiiiiiiiiii
Instead of this:
i
I want to force the user to press the key again to trigger the event.
Avoid using a keyboard related message like WM_KEYDOWN or WM_CHAR to detect a key, Windows repeats WM_KEYDOWN when the user holds it down. You simply need a your own bool flag that keeps track of the state of the key. Only change your game object state when you see a difference between the state as reported by GetAsyncKeyState() and this flag. Roughly:
bool movingLeft = false;
...
if ((GetAsyncKeyState(VK_LEFT) < 0) != movingLeft) {
movingLeft = !movingLeft;
gameObject->setVelocity(movingLeft ? -10 : 0);
}
Use KeyPress events (or KeyUp).
Btw according to MSDN SHORT WINAPI GetAsyncKeyState(__in int vKey);
Determines whether a key is up or down
at the time the function is called,
and whether the key was pressed after
a previous call to GetAsyncKeyState.
It doesn't say anything about detecting a keydown event.