The MSDN documentation says that the LParam first 15 bits is used for repeat count , but it says that it is not accumulative
Now unless i am missing something here, why does it call it a repeat count but says it is not accumulative?
This is an oxymoron statement? It says it does but it doesn't? Or am i missing something here?
I Actually tested it and masked it with bitwise operator to extract those first 15 bits with LParam&0xFFFFand no matter how much i hold down the key , this value remains as 1
Unless i am doing something wrong or missing something, i dont know what is the point of this counter which doesnt count? Or am i misunderstanding something and doing this the wrong way and there is something that needs to be done to use this
It would be much more effective and convenient to have this counter so that i dont have to run all this other code to count the repeat count for the keys pressed and held , so is it possible to be done using those first 15 bits? maybe increment those first 15 bits?
Lets start at the documentation:
The repeat count for the current message. The value is the number of times the keystroke is autorepeated as a result of the user holding down the key.
This part is relatively straight forward. The repeat count field is the number of 'presses' the key had.
If the keystroke is held long enough, multiple messages are sent.
Multiple messages can be sent, depending on your message loop. Windows will keep sending you messages as long as the key is down, so you can keep processing repeats.
However, the repeat count is not cumulative.
The repeat count doesn't carry over between messages. In other words, each message represents the number of repeats since the last time you processed a WM_KEYDOWN message.
The reason you never see a repeat count above 1 is that you're processing window messages too quickly. You can see higher numbers by putting a delay into your WM_KEYDOWN message handler to allow more repeats to queue into the next message. (In C# here because there's less boilerplate code, but you should be able to translate it to whatever language you use.)
private const int WM_KEYDOWN = 0x0100;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
System.Threading.Thread.Sleep(1000);
this.Text = $"Keydown Count: {m.LParam.ToInt32() & 0xFF}";
}
base.WndProc(ref m);
}
Running this code, I see repeat counts near 20-30.
If you need the total number of repeats, you will need to keep a running tally from the first WM_KEYDOWN until the WM_KEYUP. The design is so that you can process the events as they come in. (Picture a text box: responsiveness demands that you process the keys as they come in, rather than wait till the key is released.)
Related
I have been struggling with understand how GetKeyState operating. I have done endless google searching and haven't yet managed yet to understand exactly how it works
According to MSDN:
The key status returned from this function changes as a thread reads key messages from its message queue.
Take a look at the following code. I didn't create a message processing loop. 65 represents the virtual key of the character 'A'.
while(true) {
printf("the character %c, the vkey_state is %x",
MapVirtualKey(65, MAPVK_VK_TO_CHAR),GetKeyState(65) & 0x8000);
Sleep(150);
}
I pressed "A" on the keyboard, while being at the window console of my program.
sometimes, the vkey_state value is 0x8000 as expected, sometimes not.
What exactly is happening under the hood? I didn't write any message-processing code, so i assume it is created automatically. When I press 'A', a WM_KEYDOWN is sent to my thread message queue. When I release the key 'A', a WM_KEYUP is sent to my thread message queue. other key-related messages might be sent in between. What happens when I call GetKeyState? when exactly it will set the MSB of its return value to '1'? When will it change back to 0? Is it related to the calls to GetMessage?
In Addition - what confused me the most - is when I switched to another program (cmd.exe), and I typed 'A', my program was able to monitor it while being in the background - but cmd.exe thread has another message queue - why does it work? However - it didn't work If I started cmd.exe in elevated mode (high integrity).
this contradicts the information I found here.
If the user has switched to another program, then the GetKeyState function will not see the input that the user typed into that other program, since that input was not sent to your input queue.
Is it good idea to use MPI_Barrier() to synchronize data in-between iteration steps. Please see below pseudo code.
While(numberIterations< MaxIterations)
{
MPI_Iprobe() -- check for incoming data
while(flagprobe !=0)
{
MPI_Recv() -- receive data
MPI_Iprobe() -- loop if more data
}
updateData() -- update myData
for(i=0;i<N;i++) MPI_Bsend_init(request[i]) -- setup request
for(i=0;i<N;i++) MPI_Start(request[i]) -- send data to all other N processors
if(numberIterations = MaxIterations/2)
MPI_Barrier() -- wait for all processors -- CAN I DO THIS
numberIterations ++
}
Barriers should only be used if the correctness of the program depends on it. From your pseudocode, I can't tell if that's the case, but one barrier halfway through a loop looks very suspect.
Your code will deadlock, with or without a barrier. You receive in every rank before sending any data, so none of the ranks will ever get to a send call. Most applications will have a call such as MPI_Allreduce instead of a barrier after each iteration so all ranks can decide whether an error level is small enough, a task queue is empty, etc. and thus decide whether to terminate.
In this article http://static.msi.umn.edu/rreports/2008/87.pdf it says that you have to call MPI_Free_request() before MPI_Bsend_init().
What does "DoEvents" do in vb6 ?
Why do I get the error message "Out of stack space" ? What does it mean ?
DoEvents() allows other Windows messages to be processed.
The reason you get an out of stack space error is probably because DoEvents() is allowing events to occur that call your code again, which again calls DoEvents(), and so on until the stack space, which tracks the return addresses for all these calls, has run out.
In general, I do not recommend using DoEvents() due to problems like these and the fact that it violates the overall event-driven design of Windows.
A slightly different way of looking at DoEvents is that it flushes the events in the event queue. If your sub or function triggers an event, that event handler becomes a sub that is in line to run as soon as your sub/function is finished. DoEvents says to run that event handler sub now, instead of waiting till the end of your sub.
While I agree in spirit with Jonathon about not using DoEvents, I would temper his statement by saying I only recommend using it if you know exactly why, and know all of the repercussions of changing the order of the event queue this way. Most often, DoEvents is indicated when you want to update your screen in some way from within the context of a subroutine, before the subroutine is finished executing.
An example of this is when you are using the ProgressBar control. Suppose you are iterating through several thousand records, and want to provide feedback to the user as to how far along you are by updating a progress bar. You might interrupt your loop every hundred records and change the value on the progressbar control. However (unless you do something about it) you won't see the change on the screen until after the progressbar's change event handler runs, and that handler won't run until your sub is done executing. It will just get put in the event queue. The way to force the change event to run immediately, suspending your sub, is to call DoEvents. This will flush all existing events from the queue--in this case your progressbar's change event--and will update the progressbar control on the screen.
Now, "out of stack space" basically means that you've been caught in an endless loop of function calls. The most basic way to cause that is this:
Public sub MySub()
MySub
End Sub
And then call MySub from somewhere. You'll get an out of stack space error. If you look at the Call Stack, you'll see a very long line of calls to MySub.
A well-known real-world example of this would happen in older versions of VB:
Public Sub TextBoxArray_LostFocus(index as Integer)
If TextBoxArray(index) = "" Then
TextBoxArray(index).SetFocus
MsgBox "Please enter a value"
End If
End Sub
This situation assumes two members of a TextBox control array called TextBoxArray. Now, if the user starts with the first one (index 0) and moves to the second one (index 1) then index 0's LostFocus event will fire. However, VB would also internally set the focus to the index 1 box. Then the code would set the focus back to index 0, firing index 1's LostFocus event! You're caught in a loop. They fixed that in VB5 or 6 by waiting to set the focus until the LostFocus event was done executing.
I would clarify Johnathon's answer in that it pumps that VB message loop and allows the VB Runtime to process windows messages, which is the opposite of Sleep which allows for Windows to process its events (not necessary in the world of Multicore CPUs and true multitasking OS's but when VB6 was written Windows 9x was the dominant OS and a hard loop that only had DoEvents in it would spike the CPU usage to 100%). So seeing things like
While fDoneFile = False
DoEvents
Sleep 55
Wend
was a common pattern throughout the VB6 world.
As stated else where, DoEvents allows other events in your application to fire. Here's an example of how you can use DoEvents without the "Out of stack space" issue. This makes sure you don't run through the code multiple times by using a Boolean to indicate the code is running.
Sub Example()
'Create static variable to indicate the sub is running.
Static isRunning As Boolean
'Exit the sub if isRunning
If isRunning Then Exit Sub
'Indicate sub is running
isRunning = True
'Sub does stuff
DoEvents
'Ends up calling sub again
Example 'Added just to prove via testing.
'Indicate sub is no longer runningrunning
isRunning = False
End Sub
I have a sender, a message forwarder which sends fix sizes of byte data at a rate of 5 milliseconds per message to my receiving program written in vb6, when I run the message fowarder and my receiving program on one machine, there's no issue but when they run on separate machines, the receiving program starts to experience some abnormalities.
e.g:
private sub socket_DataArrival(index as integer, ByVal dataTotal as Long)
Dim Data() as Byte
Length.Text = dataTotal
socket.GetData byteData, vbArray + vbByte
If Length.Text = "100" Then
txtOutput.Text = "Message1"
ElseIf Length.Text = "150" Then
txtOutput.text = "Message2"
End Sub
I will sometimes receive "2 in 1" message as in it comes in as 250 bytes or a non-recognizable byte size when I should be receiving either 100 or 150 only but if I reduce the sending rate to a slower speed say 50 milliseconds per message then it will be fine.
Can anyone provide with an advice? Thanks.
When sending data over a network you have to get used to the fact that the packets may arrive out of order, not promptly, not at all, etc.
You need to improve your message protocol to include a header that states which type of message follows. If order is important include a sequence number (I'm assuming you're using UDP). At present you are relying on timing to separate messages, which you cannot rely on over a network.
Buffer all your arriving data and handle it in chunks - the header allows you to tell what chunk size to use. Separate your input buffering from your message handling - use the DataArrival event to add data to the buffer, use a Timer or some other means of polling the buffer to check if it has messages ready to parse. Alas, this is VB6 so threading is not so easy. Take a look at The Common Controls Replacement Project timer object DLL if you need a Timer class that doesn't rely on a UI element being present.
I wrote a multi-threaded windows application where thread:
A – is a windows form that handles user interaction and process the data from B.
B – occasionally generates data and passes it two A.
A thread safe queue is used to pass the data from thread B to A. The enqueue and dequeue functions are guarded using a windows critical section objects.
If the queue is empty when the enqueue function is called, the function will use PostMessage to tell A that there is data in the queue. The function checks to make sure the call to PostMessage is executed successfully and repeatedly calls PostMessage if it is not successful (PostMessage has yet to fail).
This worked well for quite some time until one specific computer started to lose the occasional message. By lose I mean that, PostMessage returns successfully in B but A never receives the message. This causes the software to appear frozen.
I have already come up with a couple acceptable workarounds. I am interesting in knowing why windows is loosing these messages and why this is only happening on the one computer.
Here is the relevant portions of the code.
// Only called by B
procedure TSharedQueue.Enqueue(AItem: TSQItem);
var
B: boolean;
begin
EnterCriticalSection(FQueueLock);
if FCount > 0 then
begin
FLast.FNext := AItem;
FLast := AItem;
end
else
begin
FFirst := AItem;
FLast := AItem;
end;
if (FCount = 0) or (FCount mod 10 = 0) then // just in case a message is lost
repeat
B := PostMessage(FConsumer, SQ_HAS_DATA, 0, 0);
if not B then
Sleep(1000); // this line of code has never been reached
until B;
Inc(FCount);
LeaveCriticalSection(FQueueLock);
end;
// Only called by A
function TSharedQueue.Dequeue: TSQItem;
begin
EnterCriticalSection(FQueueLock);
if FCount > 0 then
begin
Result := FFirst;
FFirst := FFirst.FNext;
Result.FNext := nil;
Dec(FCount);
end
else
Result := nil;
LeaveCriticalSection(FQueueLock);
end;
// procedure called when SQ_HAS_DATA is received
procedure TfrmMonitor.SQHasData(var AMessage: TMessage);
var
Item: TSQItem;
begin
while FMessageQueue.Count > 0 do
begin
Item := FMessageQueue.Dequeue;
// use the Item somehow
end;
end;
Is FCount also protected by FQueueLock? If not, then your problem lies with FCount being incremented after the posted message is already processed.
Here's what might be happening:
B enters critical section
B calls PostMessage
A receives the message but doesn't do anything since FCount is 0
B increments FCount
B leaves critical section
A sits there like a duck
A quick remedy would be to increment FCount before calling PostMessage.
Keep in mind that things can happen quicker than one would expect (i.e. the message posted with PostMessage being caught and processed by another thread before you have a chance to increment FCount a few lines later), especially when you're in a true multi-threaded environment (multiple CPUs). That's why I asked earlier if the "problem machine" had multiple CPUs/cores.
An easy way to troubleshoot problems like these is to scaffold the code with additonal logging to log every time you enter a method, enter/leave a critical section etc. Then you can analyze the log to see the true order of events.
On a separate note, a nice little optimization that can be done in a producer/consumer scenario like this is to use two queues instead of one. When the consumer wakes up to process the full queue, you swap the full queue with an empty one and just lock/process the full queue while the new empty queue can be populated without the two threads trying to lock each other's queues. You'd still need some locking in the swapping of the two queues though.
If the queue is empty when the enqueue
function is called, the function will
use PostMessage to tell A that there
is data in the queue.
Are you locking the message queue before checking the queue size and issuing the PostMessage? You may be experiencing a race condition where you check the queue and find it non-empty when in fact A is processing the very last message and is about to go idle.
To see if you're in fact experiencing a race condition and not a problem with PostMessage, you could switch to using an event. The worker thread (A) would wait on the event instead of waiting for a message. B would simply set that event instead of posting a message.
This worked well for quite some time
until one specific computer started to
lose the occasional message.
By any chance, does the number of CPUs or cores that this specific computer have different than the others where you see no problem? Sometimes when you switch from a single-CPU machine to a machine with more than one physical CPU/core, new race conditions or deadlocks may arise.
Could there be a second instance unknowingly running and eating the messages, marking them as handled?