Page 1 of 2

Sending mouse button clicks to PS2 Mouse

Posted: Thu May 08, 2008 7:53 pm
by Nitro
I'm trying to send mouse button clicks / changing mouse cursor position using the keyboard/mouse controller ports.

Anyone can give me a hand how to do this?

Thanks in advance :)

Posted: Thu May 08, 2008 9:02 pm
by bewing
Um. You don't send click or position things anywhere.

You receive the mouse packets, and the mouse tells you what clicks or movement happened in the bits in the packets. Then you store this information for your GUI to use.
Please see the Mouse Input article on the wiki for packet information.

Posted: Fri May 09, 2008 1:02 pm
by Nitro
bewing wrote:Um. You don't send click or position things anywhere.

You receive the mouse packets, and the mouse tells you what clicks or movement happened in the bits in the packets. Then you store this information for your GUI to use.
Please see the Mouse Input article on the wiki for packet information.
Thx for ur reply.

I "sent keys to the keyboard"...

So assuming that it's not possible to do the same with the mouse, how could i force the OS to "believe" that a movement was made, or that a mouse button was clicked?

I'm working under a windows nt based operating system, i need to do this at the lowest level possible, there are several ways to do this using the win32 api, or even the framework, but i need the lowest level allowed by the OS.

Posted: Fri May 09, 2008 1:34 pm
by AJ
Hi,
I believe the Win API is the lowest level you can do it at. Alternatively, try searching something like Ralph Browns Interrupt list to see if there is a direct system call you can use.

Cheers,
Adam

Posted: Fri May 09, 2008 3:16 pm
by JamesM
Hi,
I "sent keys to the keyboard"...
Your statement actually defies the logic in the keyboard controller. It recieves commands, and sends data. Not the other way around.

Posted: Fri May 09, 2008 3:41 pm
by Nitro
JamesM wrote:Hi,
I "sent keys to the keyboard"...
Your statement actually defies the logic in the keyboard controller. It recieves commands, and sends data. Not the other way around.

Code: Select all

private void sendKey(short keyPressCode)
        {
            short keyReleaseCode =(short)(0x80 + keyPressCode);
            short status;

            //Wait Input Buffer empty 
            do { status = inp(0x64); } while ((status & 2) != 0);
            outp(0x60, 0xF4); //Enable keyboard

            // Wait until i8042 can receive the command.
            do { status = inp(0x64); } while ((status & 2) != 0);
            outp(0x64, 0xD2); // Send write request
            // Wait until i8042 can receive data.
            do { status = inp(0x64); } while ((status & 2) != 0);
            outp(0x60, keyPressCode); // Write keypress code
            
            // Wait until i8042 has received the keypress code
            do { status = inp(0x64); } while ((status & 2) != 0);
            outp(0x64, 0xD2);// Send write request
            // Wait until i8042 can receive data.
            do { status = inp(0x64); } while ((status & 2) != 0);
            outp(0x60, keyReleaseCode); //write keyrelease code
            // Wait until i8042 has received the keyrelease code
            do { status = inp(0x64); } while ((status & 2) != 0);
         }
Writting to an input device thru i8042 controller, at least it works for me.

I was expecting to be able to do the same with the mouse, since it uses the i8042 controller just like the keyboard...

Posted: Fri May 09, 2008 4:39 pm
by Combuster
I've looked up the commands in the documentation, and you are *not* sending anything to the keyboard, nor the mouse. You just tell the PS2 controller to append bytes at the end of the buffer for one specific device.

Also note that doing it this way is prone to race conditions - for keyboards you can get stuck keys, and you can completely mess up packet alignment for mice.

Edit: I don't like the fact that you asked the same question in two threads. In fact, you hijacked one.

Posted: Fri May 09, 2008 5:17 pm
by Nitro
Combuster wrote:I've looked up the commands in the documentation, and you are *not* sending anything to the keyboard, nor the mouse. You just tell the PS2 controller to append bytes at the end of the buffer for one specific device.

Also note that doing it this way is prone to race conditions - for keyboards you can get stuck keys, and you can completely mess up packet alignment for mice.

Edit: I don't like the fact that you asked the same question in two threads. In fact, you hijacked one.
Well, that code does what i need it to do, so calling it "appending bytes to the buffer" or "sending keys" is irrelevant on what concerns me.

I tested it several times, on different machines and never had any problems.

What i need to know is if it's possible to do the exact same thing with the mouse, and if possible how to do it..

If u found anything that could help me i would apreciate alot if u share it with me :)

Posted: Sat May 10, 2008 4:30 am
by lukem95
Can't you do it in your driver? rather than sending clicks/movement to the hardware, just send a message to your driver and have that make the necessary changes.

Posted: Sat May 10, 2008 5:29 am
by Combuster
I have a list of commands one could send to the PS2 controller which does tells me what I need to know. If you're serious, it was another first hit on google so you should be able to find it.

The problem is however that mice send several bytes in sequence to form a packet. If you insert bytes half way through then neither the data you sent, nor the data from the mouse will make sense anymore, which is probably not what you want. So unless you have a brilliant way to avoid this problem, I doubt this is going to do what you intend to do.

Posted: Sat May 10, 2008 7:36 am
by CmpXchg
Hi!

Well, Nitro, it's no trivial task since the exact commands may differ from motherboard to motherboard. I've read my datasheet, and it appears to be possible:
Port 64 - Keyboard / Mouse Command..........................WO
This port is used to send commands to the keyboard / mouse controller. The command codes recognized by the VT8237R are listed in the table below.
Table 7. Keyboard Controller Command Codes
Code Keyboard Command Code Description
C8h Unblock Mouse Output (use before D1 to change active mode)
C9h Reblock Mouse Output (protection mechanism for D1)
D1h Write Output Port (data byte following is written to keyboard output port as if it came from keyboard)
D2h Write Keyboard Output Buffer & clear status bit-5 (write following byte to keyboard)
D3h Write Mouse Output Buffer & set status bit-5 (write following byte to mouse; put value in mouse input buffer so it appears to have come from the mouse)
D4h Write Mouse (write following byte to mouse)
(I believe the status bit is actually the bit 5 in port 64h).

But probably we can't assume it'd work on any machine. So, wouldn't it be more prudent just to invoke your driver routines (as if the kayboard code has just been received), so it will be imposiible to tell was it a real keystroke or just a fake click?

From the technical point of view, sending mouse bytes is done in the same way as with keyboard, by using the D3/D4h commands instead of D1/D2h. Unfortunately, I can't tell you what's the exact difference between D3h and D4h.

Combuster has the point: you can mess up the whole packet sequence, so take special care about this. Write your IRQ12 handler cleverly. When a packet arrives, do we get 4 interrupt calls, or can we read all 4 bytes from one call?

We could also take advantage of the C8/C9h commands, the problem is that there seems to be no reliable documentation on that.

Cheers,
CmpXchg

Posted: Sun May 11, 2008 4:26 am
by Nitro
CmpXchg wrote: But probably we can't assume it'd work on any machine. So, wouldn't it be more prudent just to invoke your driver routines (as if the kayboard code has just been received), so it will be imposiible to tell was it a real keystroke or just a fake click?
I think that will work on any machine, as far as i've read only some special command sequences may differ from hardware to hardware.

What do u mean by invoking the driver routines?
The only access to the driver provided by microsoft is thru the win32 api.
The reason why i don't want to use it, it's because a fake click/key press CAN be detected, if those routines are hooked by another program.
CmpXchg wrote: Combuster has the point: you can mess up the whole packet sequence, so take special care about this. Write your IRQ12 handler cleverly. When a packet arrives, do we get 4 interrupt calls, or can we read all 4 bytes from one call?
Unfortunatly on windows NT based systems, only drivers can access the interrupts, so that is a card out of the deck.. unless i decide to code a virtual mouse driver, wich i'm trying to avoid.

I hope there is a way to do this without having to use the interrupts.

If it was possible to "lock" and "unlock" the mouse, that shouldn't be a problem.

-wait until buffer is empty
-lock mouse
-write packet sequence for clicking/moving.
-unlock mouse

Thanks alot for your reply CmpXchg.

Posted: Sun May 11, 2008 8:13 am
by bewing
1.) You would have to completely turn off automatic packet mode, to make sure that the mouse stops at the end/beginning of a packet. Then wait a little time to make sure the last packet flushed completely.

2.) There are perhaps 100 possible mouse packet format combinations -- if we are only looking at M$ compliant mice. You need to know which one to use. You would need to read the MouseID byte to determine the major packet format. Then you would need to get the mouse resolution, so that you could scale your spoofed mouse movement properly.

3.) Every byte you request from the mouse, and all the ACKs for the commands you send, will generate IRQ12s -- which will wake up the windoze mouse driver. It will race you, to try to get that byte from the mouse port before you do, and it will win most of the time. You would probably need to shut off IRQ12 to make your scheme work properly. Shutting off IRQ12 should be impossible.

4.) You would have to stuff one packet byte at a time into the controller.

5.) For each byte, you would need to spoof an IRQ12, in order to get the windoze mouse driver to read the byte from the input. You would have to hope that the mouse driver really was using IRQ12.

6.) Then turn the mouse automatic packet mode back on.

7.) If windoze has any decent security, it should completely block most of these steps.

Posted: Sun May 11, 2008 8:35 am
by Nitro
What about using the mouse driver directly?
Would it be possible?

Anyone with experience using windows DDK?

Posted: Sun May 11, 2008 9:04 am
by CmpXchg
Ok, let us see...
Nitro wrote:The only access to the driver provided by microsoft is thru the win32 api.
The reason why i don't want to use it, it's because a fake click/key press CAN be detected, if those routines are hooked by another program.
Oh, I didn't realize you're working under an Microsoft NT-based system, I thought you're developing your own OS...
By win32 api you mean functions like mouse_event? Yes, they can be hooked by another program by means of Win32 API hooking.
Nitro wrote:Unfortunatly on windows NT based systems, only drivers can access the interrupts, so that is a card out of the deck.. unless i decide to code a virtual mouse driver, wich i'm trying to avoid.
I see. If we're working under an Nt-based system, we can't control interrupts. We can't even access I/O ports 60/64, which are required to send the commands.

To access ports & interrupts, we need to write a driver. In your earlier posts you said you wanted to do it at the lowest possible level. Well, the lowest level in NT-based systems are WDM Kernel-Mode drivers... By a virtual mouse driver, you mean a kernel-mode driver, right?
Nitro wrote:-wait until buffer is empty
-lock mouse
-write packet sequence for clicking/moving.
-unlock mouse
Unfortunately, this can only be done at kernel level. But even if we write a kernel-mode driver, we shouldn't do it directly. Why shoudln't we? Because in any NT-based system there is a standard system driver called i8042prt.sys that handles IRQ12 and ports 60,61 and 64, maybe some other as well. So we shouldn't interfere with it, as bewing has so vividly described.

So the solution that seems to me is to create a kernel-mode driver that will call i8042prt.sys functions, in hope that it is possible to simulate mouse events this way. And it would provide some API interface for Win32 applications. That will definitely require Windows DDK...

I've checked i8042prt's export table and found that it exports no functions. How are we supposed to use it, then? I'm afraid I have to ask the same question: anyone with experience in Windows DDK?