Xlib XSendEvent Custom ClientEvent - c

I'm having problem of sending my program specific event with XSendEvent().
I setup XEvent as follows and send it:
XEvent evt;
evt.xclient.type = ClientMessage;
evt.xclient.serial = 0;
evt.xclient.send_event = true;
evt.xclient.message_type = XInternAtom(xconn, "_APP_EVT", false);
evt.xclient.format = 32;
evt.xclient.window = xwin;
evt.xclient.data.l[0] = XInternAtom(xconn, "_APP_EVT_PTR", false);
*reinterpet_cast<void**>(evt.xclient.data.l+1) = <pointer_value>
XSendEvent(xconn, xwin, false, NoEventMask, &evt);
Later in event loop I try read the sent pointer from the
recived message, but the read pointer value is always bad.
So far I have no idea why Xlib even mangles the evt.xclient.data.l array,
since on XLib documentation says X won't interpet the data at all.
for(;;) {
XEvent evt;
XNextEvent(xconn, &evt);
if(evt.type == ClientMessage) {
if(evt.xclient.message_type == XInternAtom(xconn, "_APP_EVT", false)) {
if(evt.xclient.data.l[0] == XInternAtom(xconn, "_APP_EVT_PTR", false)) {
// Prints pointers,
// that have only partially corrects bits in place:
printf("_APP_EVT_PTR:%p", *reinterpet_cast<void**>(evt.xclient.data.l+1));
}
}
}
Another detail here is that the message is sent from main thread,
and the message loop is in separate GUI thread.
I call XInitThreads() on the program before doing anything else with Xlib.

Related

Arduino microphone/AMB decoder combination gets interrupted

Microphone readout gets randomly interrupted
I have a microphone hooked up to my Arduino on a Serial hardware port 2.
https://sigrok.org/wiki/Colead_SL-5868P
I receive data from the microphone by sending 0x20 to it. The following functions read out it's data.
FlushMic1 is a function to flush out the Serial2 buffer, so we can read out the correct data from the buffer.
String getMic1()
{
String valueMic;
if(flushedMic1())
{
Serial2.write(0x20);
while (Serial2.available() <= 10){;}
valueMic = "";
for (int i = 0; i < 10; i++)
{
int data = Serial2.read();
valueMic += String(data);
}
}
return valueMic;
}
bool flushedMic1()
{
bool returnBool = false;
while(Serial2.available())
{
Serial2.read();
returnBool = true;
}
return returnBool;
}
On another port I have a transponder loop connected, to measure passing transponders.
If a transponder passes it sends char to the Serial Hardware port 1. It can be detected if it includes a '#'.
bool isTransponderPassing()
{
char data = Serial1.read();
if (data == '#')
{
return true;
}
return false;
}
Running the getMic1() function in a loop works perfectly fine. If the : if(isTransponderPassing()) is used in the in main loop I sometimes get the correct data, sometimes false data, when I receive false data, the entire program gets interrupted, which propably fills the buffer with 16's and that's why we receive 16's.
Who knows where my program can get stuck?
void setup()
{
// Starts the serial monitor
Serial.begin(2400);
// Starts Serial monitor of AMB decoder
Serial1.begin(9600);
// Starts Serial monitor of microphone 1
Serial2.begin(2400);
}
void loop()
{
Serial.println(Serial2.available());
Serial.println(Serial1.available());
if(isTransponderPassing())
{
Serial.println(getMic1());
}
}
I fixed the issue, because I wasn't aware Serial.readString() in getMic1() has a delay of 1 second. So I should just read the documentation better next time.
So everyone, Serial.readString() has a delay of 1 second, hope this saves time for others!
Use Serial.readStringUntil(char ofChoice) instead, this reads the buffer into a String, but quits when it has reached the given char.
Buffer = "Hello world";
// Serial.readString() does:
delay(1000);
return Buffer;
result : "Hello world"
// Serial.readStringUntil("o") does:
return BufferUntilChar("o")
result : "Hello wo"

How to make SDL_Keypress detect new Keypress during keypress-loop?

I'm writing Conways game of life in C with SDL. The game logic and everything works fine but I want to have it when you press p for example that the game automatically updates until p is pressed again and the loop stops. Somehow it only repeats once and doesn't even register the second time p is pressed.
else if (e.key.keysym.sym == SDLK_p){
bool stop = false;
while (!stop){
nextEpoch();
updateGame(window, renderer, r);
msleep(500);
if (e.type == SDL_KEYDOWN){
if (e.key.keysym.sym == SDLK_p){
stop = true;
printf("s\n");
}
}
}
}
It doesn't register that p is pressed when it in the while-loop.
Here's the full code: https://gist.github.com/PhilippRados/2df8760cc55822c2eac62addafb24403
As already pointed out by someone else in the comments section, you are not updating e in the inner loop. If you want to update e with a new event, you must call SDL_PollEvent( &e ) again to fill it with a new event.
In your linked code, you seem to be attempting to implement a new state of your program outside the main event loop, which represents the running state of the program, whereas the main event loop represents the paused state of the program. That way, you effectively have two separate event loops, one for each state of the program. While it is possible to make your program work this way, I don't recommend it.
For example, the way you have designed your program, your program won't respond to SDL_QUIT events in the running state. It will only do so in the paused state.
Therefore, it would make more sense to have a single event loop for both the running and the paused states of your program.
I don't recommend that you call usleep or SDL_Delay for waiting until it is time to render the next frame, as your program will not be responding to user input during this time. Especially since you have a very low frame rate of 2 frames per second, this means that it will take up to half a second for your program to respond to user input (for example if the user resizes the window or attempts to close it). Instead, I recommend that you set up a timer using SDL_AddTimer. You can program the timer callback function to give you a SDL_USEREVENT event twice per second. That way, when you receive this event, you will know that it is time to update the game and render the next frame. While waiting for this event, your program will still be able to respond to other events.
Note that in order to use SDL timers, you must initialize the corresponding subsystem using the SDL_INIT_TIMER flag when calling SDL_Init. Strangely, your linked code does not seem to call SDL_Init at all, so I am surprised that your code works at all. According to the documentation, you should call SDL_Init like this:
SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO );
Also, calling SDL_PollEvent in a loop seems like a big waste of CPU resources, as your CPU usage will likely be 100% although you are effectively doing nothing most of the time. I recommend that you call SDL_WaitEvent instead, so that the thread will sleep until it receives a new event to respond to.
Another thing worth noting is that when handling an SDL_MOUSEBUTTONDOWN event, it does not seem appropriate to use the result of SDL_GetMouseState to determine the coordinates of the mouse click, as that function will return the current mouse coordinates and not the coordinates at the time of the click. Therefore, it would be more appropriate to read these coordinates from the SDL_MouseButtonEvent structure.
Here is an example of how you could rewrite your event loop to use SDL_WaitEvent instead of SDL_PollEvent and to support both a running and a paused state in the main event loop.
Uint32 my_callbackfunc( Uint32 interval, void *param )
{
SDL_Event e;
e.user.type = SDL_USEREVENT;
e.user.code = 0;
e.user.data1 = NULL;
e.user.data2 = NULL;
SDL_PushEvent( &e );
return interval;
}
int main (int argc, char** argv)
{
[...]
//set timer to trigger twice per second
SDL_TimerID timer = SDL_AddTimer( 500, my_callbackfunc, NULL );
if ( timer == 0 ) {
//TODO: handle error
return EXIT_FAILURE;
}
//start game in a paused state
bool paused = true;
while ( SDL_WaitEvent( &e ) ) {
switch ( e.type ) {
case SDL_QUIT:
goto quit_game;
case SDL_WINDOWEVENT:
//rerender in case of window state change
updateGame( window, renderer, r );
break;
case SDL_USEREVENT:
if ( !paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDL_MOUSEBUTTONDOWN:
mouseX = getNearestMultiple( e.button.x ) / RECT_SIZE;
mouseY = getNearestMultiple( e.button.y) / RECT_SIZE;
if ( Field[mouseX][mouseY] ) {
//Deactivate cell
Field[mouseX][mouseY] = false;
updateGame(window,renderer,r);
}
else {
//activate cell at position x,y
Field[mouseX][mouseY] = true;
updateGame(window,renderer,r);
}
break;
case SDL_KEYDOWN:
switch ( e.key.keysym.sym ) {
case SDLK_SPACE:
if ( paused ) {
nextEpoch();
updateGame(window, renderer, r);
}
break;
case SDLK_r:
memset(Field,0,sizeof(Field[0][0]) * WIDTH * HEIGHT);
memset(nextState,0,sizeof(nextState[0][0]) * WIDTH * HEIGHT);
updateGame(window,renderer, r);
break;
case SDLK_p:
paused = !paused;
}
}
}
quit_game:
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}

Missing packets (Windows NDIS Driver Filter)

I'm a beginner to WDD. I need to make a network driver filter that drops certain packets based on the signature to protect system from program vulnerability.
Right now, I'm just trying to get the packets I need and find my signature. I use Metasploit Framework to exploit this vulnerability and Wireshark to track the traffic. In Wireshark I see 4 packets with destination port 8000 like this:
But when I'm trying to get them I only have 2 first of them - with SYN and ACK.
My code is based on NDIS driver filter sample. I'm writing inside the FilterReceiveNetBufferLists function. Here's the code:
_Use_decl_annotations_
VOID
FilterReceiveNetBufferLists(
NDIS_HANDLE FilterModuleContext,
PNET_BUFFER_LIST NetBufferLists,
NDIS_PORT_NUMBER PortNumber,
ULONG NumberOfNetBufferLists,
ULONG ReceiveFlags
)
/*++
Routine Description:
FilerReceiveNetBufferLists is an optional function for filter drivers.
If provided, this function processes receive indications made by underlying
NIC or lower level filter drivers. This function can also be called as a
result of loopback. If this handler is NULL, NDIS will skip calling this
filter when processing a receive indication and will call the next higher
driver in the stack. A filter that doesn't provide a
FilterReceiveNetBufferLists handler cannot provide a
FilterReturnNetBufferLists handler and cannot a initiate an original receive
indication on its own.
Arguments:
FilterModuleContext - our filter context area.
NetBufferLists - a linked list of NetBufferLists
PortNumber - Port on which the receive is indicated
ReceiveFlags -
N.B.: It is important to check the ReceiveFlags in NDIS_TEST_RECEIVE_CANNOT_PEND.
This controls whether the receive indication is an synchronous or
asynchronous function call.
--*/
{
PMS_FILTER pFilter = (PMS_FILTER)FilterModuleContext;
BOOLEAN DispatchLevel;
ULONG Ref;
BOOLEAN bFalse = FALSE;
#if DBG
ULONG ReturnFlags;
#endif
DEBUGP(DL_TRACE, "===>ReceiveNetBufferList: NetBufferLists = %p.\n", NetBufferLists);
do
{
DispatchLevel = NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags);
#if DBG
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
if (pFilter->State != FilterRunning)
{
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
if (NDIS_TEST_RECEIVE_CAN_PEND(ReceiveFlags))
{
ReturnFlags = 0;
if (NDIS_TEST_RECEIVE_AT_DISPATCH_LEVEL(ReceiveFlags))
{
NDIS_SET_RETURN_FLAG(ReturnFlags, NDIS_RETURN_FLAGS_DISPATCH_LEVEL);
}
NdisFReturnNetBufferLists(pFilter->FilterHandle, NetBufferLists, ReturnFlags);
}
break;
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
#endif
ASSERT(NumberOfNetBufferLists >= 1);
////////////////////////////// MY CODE //////////////////////////////////////
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
PNET_BUFFER_LIST pCurrentNetBufferList = NetBufferLists;
PNET_BUFFER pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList);
while (pCurrentNetBufferList)
{
while (pCurrentNetBuffer)
{
ULONG netbuffer_size = NET_BUFFER_DATA_LENGTH(pCurrentNetBuffer);
BYTE* buffer = (BYTE*)NdisGetDataBuffer(
pCurrentNetBuffer,
netbuffer_size,
NULL,
1,
0);
if (buffer) {
ParseBuffer(buffer, netbuffer_size);
}
else
{
void* alloc_mem = ExAllocatePoolWithTag(PagedPool, netbuffer_size, 'BteN');
buffer = (BYTE*)NdisGetDataBuffer(
pCurrentNetBuffer,
netbuffer_size,
alloc_mem,
1,
0);
if (buffer) {
ParseBuffer(buffer, netbuffer_size);
}
else {
DbgPrint("T.T");
}
ExFreePoolWithTag(alloc_mem, 'BteN');
}
pCurrentNetBuffer = NET_BUFFER_NEXT_NB(pCurrentNetBuffer);
}
pCurrentNetBufferList = NET_BUFFER_LIST_NEXT_NBL(pCurrentNetBufferList);
}
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
////////////////////////////////////////////////////////////////////////////
//
// If you would like to drop a received packet, then you must carefully
// modify the NBL chain as follows:
//
// if NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags):
// For each NBL that is NOT dropped, temporarily unlink it from
// the linked list, and indicate it up alone with
// NdisFIndicateReceiveNetBufferLists and the
// NDIS_RECEIVE_FLAGS_RESOURCES flag set. Then immediately
// relink the NBL back into the chain. When all NBLs have been
// indicated up, you may return from this function.
// otherwise (NDIS_TEST_RECEIVE_CANNOT_PEND is FALSE):
// Divide the linked list of NBLs into two chains: one chain
// of packets to drop, and everything else in another chain.
// Return the first chain with NdisFReturnNetBufferLists, and
// indicate up the rest with NdisFIndicateReceiveNetBufferLists.
//
// Note: on the receive path for Ethernet packets, one NBL will have
// exactly one NB. So (assuming you are receiving on Ethernet, or are
// attached above Native WiFi) you do not need to worry about dropping
// one NB, but trying to indicate up the remaining NBs on the same NBL.
// In other words, if the first NB should be dropped, drop the whole NBL.
//
//
// If you would like to modify a packet, and can do so quickly, you may
// do it here. However, make sure you save enough information to undo
// your modification in the FilterReturnNetBufferLists handler.
//
//
// If necessary, queue the NetBufferLists in a local structure for later
// processing. However, do not queue them for "too long", or else the
// system's performance may be degraded. If you need to hold onto an
// NBL for an unbounded amount of time, then allocate memory, perform a
// deep copy, and return the original NBL.
//
if (pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs += NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(1, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
NdisFIndicateReceiveNetBufferLists(
pFilter->FilterHandle,
NetBufferLists,
PortNumber,
NumberOfNetBufferLists,
ReceiveFlags);
if (NDIS_TEST_RECEIVE_CANNOT_PEND(ReceiveFlags) &&
pFilter->TrackReceives)
{
FILTER_ACQUIRE_LOCK(&pFilter->Lock, DispatchLevel);
pFilter->OutstandingRcvs -= NumberOfNetBufferLists;
Ref = pFilter->OutstandingRcvs;
FILTER_LOG_RCV_REF(2, pFilter, NetBufferLists, Ref);
FILTER_RELEASE_LOCK(&pFilter->Lock, DispatchLevel);
}
} while (bFalse);
DEBUGP(DL_TRACE, "<===ReceiveNetBufferList: Flags = %8x.\n", ReceiveFlags);
}
ParseBuffer function:
VOID ParseBuffer(BYTE *buffer, ULONG netbuffer_size)
{
// parse ethernet
eth_header_t* pEthHeader = (eth_header_t*)buffer;
ASSERT(pEthHeader);
if (pEthHeader->type == RtlUshortByteSwap(EtherType_IPv4))
{
// parse ipv4
ipv4_header_t* pIpHeader = (ipv4_header_t*)(buffer + sizeof(eth_header_t));
ASSERT(pIpHeader);
ASSERT(pIpHeader->version == IPPROTO_IPV4);
if (pIpHeader->protocol == IPPROTO_TCP)
{
// parse tcp
tcp_header_t* pTcpHeader = (tcp_header_t*)(buffer + sizeof(eth_header_t) + sizeof(ipv4_header_t));
ASSERT(pTcpHeader);
if (pTcpHeader->dst_port == RtlUshortByteSwap(8000))
{
if (netbuffer_size) {}
DbgPrint("PACKET DUMP:\n");
DbgPrintHexDump(buffer, netbuffer_size);
WORD ip_total_length = RtlUshortByteSwap(pIpHeader->total_length);
WORD tcp_size = ip_total_length - sizeof(ipv4_header_t);
WORD data_size = tcp_size - (pTcpHeader->data_offset << 2);
DbgPrint("DATA SIZE: %d \n", data_size);
// if there is any data in packet
if(data_size)
{
BYTE* data = (buffer + sizeof(eth_header_t) + sizeof(ipv4_header_t) + (pTcpHeader->data_offset << 2));
ASSERT(data);
DbgPrint("Data:\n");
DbgPrintHexDump(data, data_size);
const char* signature = "\xEB\x0C / HTTP/1.1 ";
const char* pch = strstr((const char*)data, signature);
if (pch != NULL)
{
DbgPrint("Got it!\n");
}
}
DbgPrint("\n");
}
}
}
}
Maybe I have to clone NetBufferLists before processing them, I don't know. And if I have to, when should I do it?
P.S. The full code (if you need).
Well, It was a stupid mistake, I put PNET_BUFFER pCurrentNetBuffer = NET_BUFFER_LIST_FIRST_NB(pCurrentNetBufferList) in the wrong place. It has to be right after while (pCurrentNetBufferList).

Creating an asynchronous "ReadFileMany()" on top of ReadFile()

I'm trying to make a function, ReadFileMany, which imitates ReadFile's interface, which is given a list of (offset, length) pairs to read from, and which reads all portions of the file asynchronously.
I'm doing this inside ReadFileMany by using RegisterWaitForSingleObject to direct a thread pool thread to wait for I/O to complete, so that it can call ReadFile again to read the next portion of the file, etc.
The trouble I'm running into is that I can't seem to be able to mimic a certain behavior of ReadFile.
Specifically, file handles can themselves be used like events, without the need for an event handle:
OVERLAPPED ov = {0};
DWORD nw;
if (ReadFile(hFile, buf, buf_size, &nw, &ov))
{
if (WaitForSingleObject(hFile, INFINITE) == WAIT_OBJECT_0)
{
...
}
}
but of course, if the user waits on a file handle, he might get a notification that an intermediate read has complete, rather than the final read.
So, inside ReadFileMany, I have no choice but to pass an hEvent parameter to ReadFile for all but the last portion.
The question is, is there any way to still allow the user to wait for the file handle to become signaled when all the portions have been read?
At first the answer seems obvious: just avoid passing an event handle when reading the last portion!
That works fine if the read will be successful, but not if there are errors. If ReadFile starts suddenly returning an error on the last read, I will need to set the file handle to a signaled state manually in order to allow the reader to wake up from his potential call to WaitForSingleObject(hFile).
But there seems to be no way to set a file handle to a signaled state without performing actual I/O... so this is where I get stuck: is there any way for me to write this function so that it behaves like ReadFile on the outside, or is it impossible to do it correctly?
Assuming you are trying to read multiple sections of a single file, I would simply allocate an array of OVERLAPPED structures, one for each requested section of the file, kick off all of the ReadFile() calls at one time, and then use WaitForMultipleObjects() to wait for all of the I/Os to finish, eg:
struct sReadInfo
{
OVERLAPPED ov;
LPVOID pBuffer;
DWORD dwNumBytes;
DWORD dwNumBytesRead;
bool bPending;
sReadInfo()
{
memset(&ov, 0, sizeof(OVERLAPPED));
pBuffer = NULL;
dwNumBytes = 0;
dwNumBytesRead = 0;
bPending = false;
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!ov.hEvent) throw std::exception();
}
~sReadInfo()
{
CloseHandle(hEvent);
}
};
.
bool error = false;
try
{
std::vector<sReadInfo> ri(numSections);
std::vector<HANDLE> h;
h.reserve(numSections);
for(int i = 0; i < numSections; ++i)
{
ULARGE_INTEGER ul;
ul.QuadPart = ...; // desired file offset to read from
sReadInfo *r = &ri[i];
r->ov.Offset = ul.LowPart;
r->ov.OffsetHigh = ul.HighPart;
r->pBuffer = ...; // desired buffer to read into
r->dwNumBytes = ...; // desired number of bytes to read
if (!ReadFile(hFile, r->pBuffer, r->dwNumBytes, &r->dwNumBytesRead, &r->ov))
{
if (GetLastError() != ERROR_IO_PENDING)
throw std::exception();
r->bPending = true;
h.push_back(r->ov.hEvent);
}
}
if (!h.empty())
{
if (WaitForMultipleObjects(h.size(), &h[0], TRUE, INFINITE) != WAIT_OBJECT_0)
throw std::exception();
}
for (int i = 0; i < numSections; ++i)
{
sReadInfo *r = &ri[i];
if (r->bPending)
GetOverlappedResult(hFile, &r->ov, &r->dwNumBytesRead, FALSE);
// ...
}
}
catch (const std::exception &)
{
CancelIo(hFile);
return false;
}
return true;

How to trigger or simulate keyboard interrupt?

I'm writing a keyboard filter driver for Windows and I need to insert my custom keystrokes data into Windows message queue. I've managed to capture all the keys that are pressed setting OnReadCompletion() callback to IoSetCompletionRoutine() in my driver's Read() function like so:
NTSTATUS Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, OnReadCompletion, DeviceObject, TRUE, TRUE, TRUE);
return IoCallDriver (deviceExtension->pKeyboardDevice, Irp);
}
NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
// ...
}
This filter driver is attached to the kbdclass driver like so:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
// ...
CCHAR ntNameBuffer[64] = "\\Device\\KeyboardClass0";
status = IoAttachDevice(deviceObject, &uKeyboardDeviceName, &DeviceExtension->pKeyboardDevice);
// ...
}
So, I can catch all keys pressed in OnReadCompletion(). But I need to insert my own information into keyboard message flow. Here are 2 problems with that:
OnReadCompletion() is only invoked when a key pressed. Ideally I'd like somehow it to be called when nothing is pressed. Can I do that somehow? I need to trigger a keyboard interrupt? I tried to write commands to a keyboard ports (0x60 and 0x64) with WRITE_PORT_UCHAR() but that didn't work out.
I tried to insert my data into IRP in OnReadCompletion() to make it look like for example a key was pressed twice while actually it was pressed only once. Can someone help me out on that one too, because the following didn't work out?
NTSTATUS OnReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
PIO_STACK_LOCATION IrpStackLocation = NULL;
INT BufferLength;
INT numKeys = 0, i = 0;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
IrpStackLocation = IoGetCurrentIrpStackLocation(Irp);
BufferLength = IrpStackLocation->Parameters.Read.Length;
if(Irp->IoStatus.Status == STATUS_SUCCESS)
{
PCHAR newSystemBuffer, oldSystemBuffer;
PKEYBOARD_INPUT_DATA keys = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA);
for(i = 0; i < numKeys; i++)
{
// here we print whatever was pressed
DbgPrint("%s -- ScanCode: %x\n", __FUNCTION__, keys[i].MakeCode);
}
// allocate new buffer twice as big as original
newSystemBuffer = ExAllocatePool(NonPagedPool, Irp->IoStatus.Information * 2);
// copy existing buffer twice into new buffer
RtlCopyMemory(newSystemBuffer, keys, Irp->IoStatus.Information);
RtlCopyMemory(newSystemBuffer + Irp->IoStatus.Information, keys, Irp->IoStatus.Information);
// assign new buffer to Irp->AssociatedIrp.SystemBuffer
oldSystemBuffer = Irp->AssociatedIrp.SystemBuffer;
Irp->AssociatedIrp.SystemBuffer = newSystemBuffer;
// tell IRP that we now have twice as much data
Irp->IoStatus.Information *= 2;
// free the old buffer
ExFreePool(oldSystemBuffer);
}
if(Irp->PendingReturned)
IoMarkIrpPending(Irp);
return Irp->IoStatus.Status;
}
And when I test it for example in Notepad, all I get is just one letter per keystroke.
I'm really desperate. Please help!
Four options which I think should work:
1) You could create a new IRP to call the kbdclass driver with, as opposed to passing the IRP that you received down. You would complete the original IRP whenever you wanted to insert data as well as whenever you had real keystrokes to pass on.
2) You could have two devices, the second being a keyboard device. You would then use the kbdclass filter for removing keystrokes and the keyboard device for adding them.
3) You could redesign your driver to be an upper filter for the keyboard devices, similar to the MSDN sample driver kbfiltr.
4) You could have two devices, the second being an upper filter for one or more of the keyboard devices. You would use the kbdclass filter for removing keystrokes and the keyboard device filter for adding them.
I think the first option would be best, but I'm no expert.

Resources