fruit-bat / pico-zxspectrum

ZX Spectrum for Raspberry Pico Pi RP2040
474 stars 52 forks source link

Kempston Mouse #145

Closed javavi closed 1 month ago

javavi commented 3 months ago

Since there is already support for USB HID devices, is it possible to ask to add support for Kempston Mouse to the emulator? image https://sinclair.wiki.zxnet.co.uk/wiki/Kempston_Mouse https://velesoft.speccy.cz/kmturbo2008-cz.htm https://velesoft.speccy.cz/kmsoft.htm https://zxart.ee/eng/software/game/hw:kempstonmouse/statuses:allowed,forbidden,insales,recovered,unknown,unreleased/sorting:votes,desc https://www.youtube.com/playlist?list=PLxOanVBhqd3tM1Ov2sGHI177WdlY0wali

fruit-bat commented 3 months ago

I think it should be possible, but I've not tried using mice with TinyUSB. Will have a look when I get time.

javavi commented 3 months ago

image Program for testing all ports of the ZX Spectrum computer PD.ZIP

javavi commented 3 months ago

I think that you should not have any problems adding a USB HID mouse to the Menu System, since there are many examples using the TinyUSB library on GitHub. But I can help with adding Kempston Mouse ports to the emulator and testing. I hope you have time for our hobby!) Best regards.

On Wed, Jun 26, 2024, 23:50 fruit-bat @.***> wrote:

I think it should be possible, but I've not tried using mice with TinyUSB. Will have a look when I get time.

— Reply to this email directly, view it on GitHub https://github.com/fruit-bat/pico-zxspectrum/issues/145#issuecomment-2192605182, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQJPRDE5QOMUN5DSJCLR76DZJMSQ3AVCNFSM6AAAAABJ2R2FTKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCOJSGYYDKMJYGI . You are receiving this because you authored the thread.Message ID: @.***>

fruit-bat commented 3 months ago

Just a start...

Draft pull requests here so you can see what is going on...

https://github.com/fruit-bat/pico-zxspectrum/pull/146/ https://github.com/fruit-bat/pico-emu-utils/pull/8

@javavi thanks for the offer help. The test program is really handy. I have just routed the mouse events into emulator. I think I need to have a read about how mouse messages are delivered to the Spectrum. Please remind me which firmware you use and I can post test build here for you to play about with.

fruit-bat commented 3 months ago

The code on those branches works now. It's only compiling for the HDMI targets at the moment. I will sort the others shortly.

javavi commented 3 months ago

Please remind me which firmware you use and I can post test build here for you to play about with.

I can use MURMULATOR with USB Hub for testing and also attract help from the community for these purposes.

fruit-bat commented 3 months ago

Please remind me which firmware you use and I can post test build here for you to play about with.

I can use MURMULATOR with USB Hub for testing and also attract help from the community for these purposes.

Please remind me which firmware you use and I can post test build here for you to play about with.

I can use MURMULATOR with USB Hub for testing and also attract help from the community for these purposes.

This any good to you?

ZX-MURMULATOR_HDMI_HDMI_AUDIO_720x576x50Hz.uf2.zip

fruit-bat commented 3 months ago

Here are the rest of them.... let me know how you get on with them.

There is an indicator on the menu which should say 'mice: 1' when a mouse is connected.

ZX-MURMULATOR_ALL.zip

javavi commented 3 months ago

For now I've checked it on the firmware I compiled myself from the mouse branch. I tried a couple of games and it works! Of the comments I found, the mouse scroll wheel doesn't work, it should be reflected in the state of the D4-D7 bits of the #FADF button state port And one unnamed Chinese mouse only works in the up and down directions, I don't know why. Ports

FADF — port for buttons and (according to the domestic standard) wheel.

D0: right button (0=pressed) D1: left button (0=pressed) D2: middle button (0=pressed) D3: reserved for another button (0=pressed) D4-D7: wheel coordinate

FBDF — X-coordinate (increases from left to right)

FFDF — Y-coordinate (increases from bottom to top)

fruit-bat commented 3 months ago

Thanks for the info above.

I'm struggling with getting the mouse wheel to work. My mouse is reporting 'boot mode' and I'm not sure how to persuade TinyUSB to do otherwise. I've been messing about in hid_app.c but nothing I have tried gets the mouse to reply according to the HID report which it delivers. Help gratefully received!

fruit-bat commented 3 months ago

Just so I remember, this is the HID report delivered from my mouse....

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x02,        // Usage (Mouse)
0xA1, 0x01,        // Collection (Application)
0x09, 0x01,        //   Usage (Pointer)
0xA1, 0x00,        //   Collection (Physical)
0x05, 0x09,        //     Usage Page (Button)
0x19, 0x01,        //     Usage Minimum (0x01)
0x29, 0x03,        //     Usage Maximum (0x03)
0x15, 0x00,        //     Logical Minimum (0)
0x25, 0x01,        //     Logical Maximum (1)
0x95, 0x08,        //     Report Count (8)
0x75, 0x01,        //     Report Size (1)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
0x09, 0x30,        //     Usage (X)
0x09, 0x31,        //     Usage (Y)
0x09, 0x38,        //     Usage (Wheel)
0x15, 0x81,        //     Logical Minimum (-127)
0x25, 0x7F,        //     Logical Maximum (127)
0x75, 0x08,        //     Report Size (8)
0x95, 0x03,        //     Report Count (3)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //   End Collection
0xC0,              // End Collection

// 46 bytes
javavi commented 3 months ago

I know for example that PS/2 mice require a special initialization sequence from the host to make the scroll wheel work. A mouse without a scroll wheel sends packets of three bytes, and a mouse with a wheel sends packets of four bytes. To "turn on the wheel" the computer sends the sequence to the mouse: 0xF3, 200, 0xF3, 100, 0xF3, 80, 0xF2 (the mouse responds to each of these bytes with ACK = 0xFA). The last command here is GET_DEVICE_ID = 0xF2. After this sequence, the mouse must send an ID. If it receives zero, then the wheel is not there and will not be. If it receives "3", then the scroll wheel is on. But that's not all there is to programming. The mouse will "move slowly" if you do nothing else. Usually the mouse speed is increased by programming something like this, sending commands: 0xE8, 3, 0xE6, 0xF3, 40, and finally you need to enable transmission by sending the command 0xF4.

fruit-bat commented 3 months ago

Thanks @javavi ... I've made a little progress. The following change in TinyUSB seems to make the mouse operate according to the report it delivered (along with some changes to hid_app.c in the spectrum emulator). Not sure what other problems the change to TinyUSB might cause + I need to make it configurable.

diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c
index 1de653612..9aec6c785 100644
--- a/src/class/hid/hid_host.c
+++ b/src/class/hid/hid_host.c
@@ -575,7 +575,7 @@ static void process_set_config(tuh_xfer_t* xfer)
     break;

     case CONFIG_SET_PROTOCOL:
-      _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_BOOT, process_set_config, CONFIG_GET_REPORT_DESC);
+      _hidh_set_protocol(daddr, p_hid->itf_num, HID_PROTOCOL_REPORT, process_set_config, CONFIG_GET_REPORT_DESC);
     break;

     case CONFIG_GET_REPORT_DESC:
@@ -760,4 +760,4 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* report_info_arr,
   return report_num;
 }
 */
fruit-bat commented 3 months ago

I've pushed some changes to:

If you want to try them out, you will need to make the above change to TinyUSB.

It needs lots of tidying up... but I think everything still works.

fruit-bat commented 3 months ago

I've pushed some changes to:

javavi commented 3 months ago

Either I assembled it crookedly, or it broke!? Now the mouse that worked (Logitech M325) does not work with left/right movements, and when moving forward or backward, it turns the wheel (according to the test). The buttons are pressed normally. A Chinese unnamed mouse (connected in parallel to the Hub) works left/right, and moves up/down with a wheel (according to the test)

fruit-bat commented 3 months ago

Can you get me the HID report descriptor of your mouse? (I know roughly where these live on a linux system)

javavi commented 3 months ago

Can you get me the HID report descriptor of your mouse? (I know roughly where these live on a linux system) I have a programming environment set up on Windows 11, but I also have a Raspberry Pi 4. But I don't know where to look, since I'm just a user and don't have much experience with Linux. But I follow the instructions very nice, forgive my English :)) PS: And one more thing, maybe there is another, more interactive way of communication than here, for example Google chat? (I must have an email address in my profile.)

javavi commented 3 months ago

💡Idea! Is it possible to come up with an algorithm for using a mouse instead of a regular Kempston Joystick!? (as an option) For example: move the mouse to the left - goes, a little back - stop, more back - changes direction, and so on in all two directions. Like a Schmitt trigger, i.e. with a certain threshold for switching. Do you think this usage scenario will work for some games?

fruit-bat commented 3 months ago

Can you get me the HID report descriptor of your mouse? (I know roughly where these live on a linux system) I have a programming environment set up on Windows 11, but I also have a Raspberry Pi 4. But I don't know where to look, since I'm just a user and don't have much experience with Linux. But I follow the instructions very nice, forgive my English :)) PS: And one more thing, maybe there is another, more interactive way of communication than here, for example Google chat? (I must have an email address in my profile.)

On your Pi 4, plug in the mouse and then open a terminal. Type:

sudo usbhid-dump 

and then post the response.

P.S. the quality of my English is pretty varied :-)

javavi commented 3 months ago

This is a dump of the HID descriptor for a Logitech keyboard and mouse connected via a single Logitech Unifying dongle. pi@raspberrypi:~ $ sudo usbhid-dump 001:007:002:DESCRIPTOR 1719736417.687266 06 00 FF 09 01 A1 01 85 10 75 08 95 06 15 00 26 FF 00 09 01 81 00 09 01 91 00 C0 06 00 FF 09 02 A1 01 85 11 75 08 95 13 15 00 26 FF 00 09 02 81 00 09 02 91 00 C0 06 00 FF 09 04 A1 01 85 20 75 08 95 0E 15 00 26 FF 00 09 41 81 00 09 41 91 00 85 21 95 1F 15 00 26 FF 00 09 42 81 00 09 42 91 00 C0

001:007:001:DESCRIPTOR 1719736417.691989 05 01 09 02 A1 01 85 02 09 01 A1 00 05 09 19 01 29 10 15 00 25 01 95 10 75 01 81 02 05 01 16 01 F8 26 FF 07 75 0C 95 02 09 30 09 31 81 06 15 81 25 7F 75 08 95 01 09 38 81 06 05 0C 0A 38 02 95 01 81 06 C0 C0 05 0C 09 01 A1 01 85 03 75 10 95 02 15 01 26 FF 02 19 01 2A FF 02 81 00 C0 05 01 09 80 A1 01 85 04 75 02 95 01 15 01 25 03 09 82 09 81 09 83 81 60 75 06 81 03 C0 06 BC FF 09 88 A1 01 85 08 19 01 29 FF 15 01 26 FF 00 75 08 95 01 81 00 C0

001:007:000:DESCRIPTOR 1719736417.695240 05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01 75 01 95 08 81 02 81 03 95 05 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06 75 08 15 00 26 A4 00 05 07 19 00 2A A4 00 81 00 C0

And this dump is a HID descriptor for an unnamed Chinese wireless mouse. pi@raspberrypi:~ $ sudo usbhid-dump 001:009:001:DESCRIPTOR 1719736845.352085 05 01 09 02 A1 01 85 01 09 01 A1 00 05 09 19 01 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31 16 01 F8 26 FF 07 75 10 95 02 81 06 09 38 15 81 25 7F 75 08 95 01 81 06 05 0C 0A 38 02 95 01 81 06 C0 C0 05 01 09 80 A1 01 85 02 05 01 19 81 29 88 15 00 25 01 95 08 75 01 81 06 C0 05 0C 09 01 A1 01 85 03 15 00 26 80 03 19 00 2A 80 03 75 10 95 01 81 00 C0 06 00 FF 09 0E A1 01 85 BA 95 1F 75 08 26 FF 00 15 00 09 01 91 02 85 BA 95 1F 75 08 26 FF 00 15 00 09 01 81 02 C0

001:009:000:DESCRIPTOR 1719736845.354811 06 BC FF 09 88 A1 01 85 04 19 00 2A FF 00 15 00 26 FF 00 75 08 95 01 81 00 C0

fruit-bat commented 3 months ago

So I think this is your mouse...

0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x02,        // Usage (Mouse)
0xA1, 0x01,        // Collection (Application)
0x85, 0x02,        //   Report ID (2)
0x09, 0x01,        //   Usage (Pointer)
0xA1, 0x00,        //   Collection (Physical)
0x05, 0x09,        //     Usage Page (Button)
0x19, 0x01,        //     Usage Minimum (0x01)
0x29, 0x10,        //     Usage Maximum (0x10)
0x15, 0x00,        //     Logical Minimum (0)
0x25, 0x01,        //     Logical Maximum (1)
0x95, 0x10,        //     Report Count (16)
0x75, 0x01,        //     Report Size (1)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
0x16, 0x01, 0xF8,  //     Logical Minimum (-2047)
0x26, 0xFF, 0x07,  //     Logical Maximum (2047)
0x75, 0x0C,        //     Report Size (12)
0x95, 0x02,        //     Report Count (2)
0x09, 0x30,        //     Usage (X)
0x09, 0x31,        //     Usage (Y)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x81,        //     Logical Minimum (-127)
0x25, 0x7F,        //     Logical Maximum (127)
0x75, 0x08,        //     Report Size (8)
0x95, 0x01,        //     Report Count (1)
0x09, 0x38,        //     Usage (Wheel)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x0C,        //     Usage Page (Consumer)
0x0A, 0x38, 0x02,  //     Usage (AC Pan)
0x95, 0x01,        //     Report Count (1)
0x81, 0x06,        //     Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              //   End Collection
0xC0,              // End Collection
0x05, 0x0C,        // Usage Page (Consumer)
0x09, 0x01,        // Usage (Consumer Control)
0xA1, 0x01,        // Collection (Application)
0x85, 0x03,        //   Report ID (3)
0x75, 0x10,        //   Report Size (16)
0x95, 0x02,        //   Report Count (2)
0x15, 0x01,        //   Logical Minimum (1)
0x26, 0xFF, 0x02,  //   Logical Maximum (767)
0x19, 0x01,        //   Usage Minimum (Consumer Control)
0x2A, 0xFF, 0x02,  //   Usage Maximum (0x02FF)
0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
0x09, 0x80,        // Usage (Sys Control)
0xA1, 0x01,        // Collection (Application)
0x85, 0x04,        //   Report ID (4)
0x75, 0x02,        //   Report Size (2)
0x95, 0x01,        //   Report Count (1)
0x15, 0x01,        //   Logical Minimum (1)
0x25, 0x03,        //   Logical Maximum (3)
0x09, 0x82,        //   Usage (Sys Sleep)
0x09, 0x81,        //   Usage (Sys Power Down)
0x09, 0x83,        //   Usage (Sys Wake Up)
0x81, 0x60,        //   Input (Data,Array,Abs,No Wrap,Linear,No Preferred State,Null State)
0x75, 0x06,        //   Report Size (6)
0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection
0x06, 0xBC, 0xFF,  // Usage Page (Vendor Defined 0xFFBC)
0x09, 0x88,        // Usage (0x88)
0xA1, 0x01,        // Collection (Application)
0x85, 0x08,        //   Report ID (8)
0x19, 0x01,        //   Usage Minimum (0x01)
0x29, 0xFF,        //   Usage Maximum (0xFF)
0x15, 0x01,        //   Logical Minimum (1)
0x26, 0xFF, 0x00,  //   Logical Maximum (255)
0x75, 0x08,        //   Report Size (8)
0x95, 0x01,        //   Report Count (1)
0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0,              // End Collection

// 148 bytes

Which is quite different to my M100. I think it needs a handler for the hid descriptor similar to the one I wrote for joysticks... I'll have a go but it is a little involved so might take a while. To give you an idea, these are the ones I wrote for a simple joystick:

https://github.com/fruit-bat/pico-emu-utils/blob/feature/mouse/src/hid_host_joy.c https://github.com/fruit-bat/pico-emu-utils/blob/feature/mouse/src/hid_host_joy.h

I pull requested this stuff back to TinyUSB ages ago, but it never got merged :-(

fruit-bat commented 3 months ago

I have added a 'report' based handler for a mouse, ready for you to try :-)

See: https://github.com/fruit-bat/pico-emu-utils/blob/feature/mouse/src/hid_host_mouse.h https://github.com/fruit-bat/pico-emu-utils/blob/feature/mouse/src/hid_host_mouse.c

I would not place any bets on it working at all... but let me know if it does anything interesting.

javavi commented 3 months ago

but let me know if it does anything interesting.

Yes, on 3 simple wired mice it works correctly, including the scroll wheel! Even on one apparently simple wireless one too. But on the other 4 wireless ones it doesn't work correctly, only the buttons work normally, and when moving up/down it "spins the wheel" or moves left/right, etc.

fruit-bat commented 3 months ago

I 'found/borrowed' a Logitech M325, which I am now testing with and it works very nicely.

Make sure you have 'pulled':

I will check to see if I have done something stupid in the code... but not spotted anything yet.

fruit-bat commented 3 months ago

I can also confirm a working Logitech M330

javavi commented 3 months ago

Make sure you have 'pulled':

Yes, I messed something up, now I reassembled it and everything worked as it should! Congratulations!!!

javavi commented 3 months ago

💡How do you like this idea! Make it an option to use the mouse as a joystick. Come up with an algorithm for using the mouse instead of a joystick, for example: move the mouse to the left - it moves, a little back - stops, even back - changes direction, and so on in all two directions. Works on hysteresis, like a Schmitt trigger, i.e. with a certain switching threshold. Do you think this usage scenario could be suitable for some games?

fruit-bat commented 3 months ago

💡How do you like this idea! Make it an option to use the mouse as a joystick. Come up with an algorithm for using the mouse instead of a joystick, for example: move the mouse to the left - it moves, a little back - stops, even back - changes direction, and so on in all two directions. Works on hysteresis, like a Schmitt trigger, i.e. with a certain switching threshold. Do you think this usage scenario could be suitable for some games?

I think it is possible but probably quite a trick to make it work nicely. e.g. swapping from left -> right, you would want to do it quickly but also would need a big movement to 'show' you aren't trying to centre. I'll have a think.

fruit-bat commented 3 months ago

Some tidy-ups pushed to:

javavi commented 2 months ago

Kempston Mouse works great, Thank you very much! Now, how about the "Mouse as a joystick" mode?

fruit-bat commented 2 months ago

Kempston Mouse works great, Thank you very much! Now, how about the "Mouse as a joystick" mode?

yup, will have a go

fruit-bat commented 2 months ago

See new branch feature/mousejoy Not configurable at the moment and always acts as the left joystick. Good enough for deciding if it is good enough! Have a play.

The 'magic' happens in here: https://github.com/fruit-bat/pico-zxspectrum/blob/feature/mousejoy/src/ZxSpectrumHidMouseJoystick.cpp

Feel free to make it better!

javavi commented 2 months ago

See new branch feature/mousejoy Probably, it is necessary to make an option of the Mouse-Joystick mode. Since it works now, it may be suitable for some games - I checked it on the "Old Tower" But for "Exelon" and others, such a mode will not work. Here, we need to pick up the direction of the trigger with a release hysteresis when rolling back. In general, we will need to look at it and improve it. Thank you.

fruit-bat commented 2 months ago

Give this a go. I'm not sure it is usable but maybe have a play and see what you think. It is really tricky to not make it really annoying to use. Maybe have a play with the code and see if you can make it better.

fruit-bat commented 2 months ago

PS. Probably need to get rid of the divides and only use shifts (depending on what the compiler is doing with them).

javavi commented 2 months ago

Hello! I improved the algorithm for using a mouse instead of a joystick. Version 2. Need to test it, maybe there will be some comments? ZxSpectrumHidMouseJoystick.zip

fruit-bat commented 2 months ago

Hello! I improved the algorithm for using a mouse instead of a joystick. Version 2. Need to test it, maybe there will be some comments? ZxSpectrumHidMouseJoystick.zip

I've added your changes to the mousehoy branch :-). I will have a think about adding a menu option.

fruit-bat commented 2 months ago

I've added them menu option... but it doesn't all fit together yet. I might need to merge the mouse and mouse-joystick into one class.

fruit-bat commented 2 months ago

Menu options now working :-)

I'm probably going to remove ZxSpectrumHidMouseJoystick.cpp & ZxSpectrumHidMouseJoystick.h

Let me know if it still works.

javavi commented 2 months ago

Yes. Everything works fine and the menu is also fine. I tested it a bit with games, played with the parameters and simplified the algorithm for the mouse to work as a joystick. Version 3. ZxSpectrumHidMouseJoystick_VAR3.zip

fruit-bat commented 2 months ago

Many thanks; I've added it to branch.

javavi commented 2 months ago

It is also necessary to make sure that when the machine is reset or when selecting options, the input devices are initialized to their initial state (the mouse-as-joystick algorithm). Some games, when they start up and see a non-zero state on the Kempston joystick port, then do not work with it. For example: ALIENS NEOPLASMA

fruit-bat commented 2 months ago

Wired up the 'reset' :-)

javavi commented 2 months ago

Wired up the 'reset' :-)

Yes, now OK! the joystick states are reset when resetting, loading game images and changing mouse menu settings

fruit-bat commented 2 months ago

Excellent, you happy for me to merge this back to main?