Amiga.org
Operating System Specific Discussions => Amiga OS => Amiga OS -- Development => Topic started by: balrogsoft on May 29, 2006, 12:40:57 AM
-
Hi, i saw a interesting page with all games that support 4 player adaptor, and i have a idea that i don't know if it can work.
I played with Blitz Basic 2 and my new 4 players adaptor on my Amiga 600, i made some asm functions to read player 3 and 4 joysticks, and it work perfectly, i used an asm example on aminet.
Some games have options to play with 4 players, 2 players on joystick and 2 players on keyboard, i want to make a program that redirect player 3 and 4 joysticks to Amiga keyboard, then a lot of games will be able to use the 4 players adaptor. I only made small asm programs some years ago, i have some Amiga programming books, but i don't find a way to simulate a key press event, exist a method to make it work? and for no-multitask games also? somebody knows how to make it in assembler?
-
;
; send input event with input.device v1.0.0
;
; Written by Harry Sintonen. Public Domain.
;
include "exec/types.i"
include "exec/nodes.i"
include "exec/ports.i"
include "exec/lists.i"
include "devices/input.i"
include "devices/inputevent.i"
_LVOFindTask EQU -294
_LVOAllocSignal EQU -330
_LVOFreeSignal EQU -336
_LVOOpenDevice EQU -444
_LVOCloseDevice EQU -450
_LVODoIO EQU -456
STRUCTURE iedata,ie_SIZEOF
ALIGNLONG
LABEL iedata_SIZE
main:
lea -iedata_SIZE(sp),sp
; send key a press with left shift
move.b #IECLASS_RAWKEY,ie_Class(sp)
clr.b ie_SubClass(sp)
move.w #$20,ie_Code(sp)
move.w #IEQUALIFIER_LSHIFT,ie_Qualifier(sp)
clr.l ie_EventAddress(sp)
move.l sp,a0
bsr sendevent
; send key a release with left shift
move.b #IECLASS_RAWKEY,ie_Class(sp)
clr.b ie_SubClass(sp)
move.w #$20|IECODE_UP_PREFIX,ie_Code(sp)
move.w #IEQUALIFIER_LSHIFT,ie_Qualifier(sp)
clr.l ie_EventAddress(sp)
move.l sp,a0
bsr sendevent
lea iedata_SIZE(sp),sp
moveq #0,d0
rts
STRUCTURE data,0
STRUCT data_mp,MP_SIZE
STRUCT data_ioreq,IOSTD_SIZE
ALIGNLONG
LABEL data_SIZE
; send inputevent
; IN: a0 = inputevent to send
; OUT: d0 = zero for error, nonzero for success
sendevent:
movem.l d2/a2/a6,-(sp)
move.l (4).w,a6
move.l a0,a2
moveq #0,d2
lea -data_SIZE(sp),sp
; init msgport
moveq #-1,d0
jsr _LVOAllocSignal(a6)
move.b d0,data_mp+MP_SIGBIT(sp)
bmi .nosignal
move.b #NT_MSGPORT,data_mp+LN_TYPE(sp)
move.b #PA_SIGNAL,data_mp+MP_FLAGS(sp)
sub.l a1,a1
jsr _LVOFindTask(a6)
move.l d0,data_mp+MP_SIGTASK(sp)
lea data_mp+MP_MSGLIST(sp),a0
NEWLIST a0
; init ioreq
move.b #NT_REPLYMSG,data_ioreq+LN_TYPE(sp)
lea data_mp(sp),a0
move.l a0,data_ioreq+MN_REPLYPORT(sp)
move.w #IOSTD_SIZE,data_ioreq+MN_LENGTH(sp)
; open input.device
lea .inputname(pc),a0
moveq #0,d0
moveq #0,d1
lea data_ioreq(sp),a1
jsr _LVOOpenDevice(a6)
tst.b d0
bne .noinput
; send input event
lea data_ioreq(sp),a1
move.w #IND_WRITEEVENT,IO_COMMAND(a1)
move.l a2,IO_DATA(a1)
jsr _LVODoIO(a6)
tst.b d0
seq d2
; close input.device
lea data_ioreq(sp),a1
jsr _LVOCloseDevice(a6)
.noinput:
; free the signal
moveq #0,d0
move.b data_mp+MP_SIGBIT(sp),d0
jsr _LVOFreeSignal(a6)
.nosignal:
lea data_SIZE(sp),sp
move.l d2,d0
movem.l (sp)+,d2/a2/a6
rts
.inputname:
dc.b 'input.device',0
CNOP 0,2
Read input.device/IND_WRITEEVENT autodoc for more details.
and for no-multitask games also?
I'm afraid there is no way to do that. Only OS friendly apps will get the input events...
-
Thanks a lot, Piru! I think that exist a way to make it work with no multitasking games, but this piece of code can be usefull. I will try after work and will see how many games will work with it. There is a site where i can download Amiga include files for assembler? i found a web with AsmOne but it don't have includes.
-
I think you should contact those guys that make whdload game loaders. Ask them how they made for eg. F10 exit the game. But its probably veeery difficult and time consuming disassembling nondos games..
-
There is a site where i can download Amiga include files for assembler?
NDK3.9.lzx (http://aweb.sunsite.dk/files/dev/NDK3.9.lzx)
The assembler includes are in NDK_3.9/Include/include_i/
To comple the source code with phxass, unarchive the NDK3.9.lzx and then: phxass I=whatever:is/the/path/NDK_3.9/Include/include_i sendevent.asm
-
I think you should contact those guys that make whdload game loaders. Ask them how they made for eg. F10 exit the game.
That is completely different thing, it would require patches for every imaginable game.
Hardly useful for generic joy->keyboard patch.
-
Piru wrote:
That is completely different thing, it would require patches for every imaginable game.
Hardly useful for generic joy->keyboard patch.
Different but not at all, WHDLoad execute a routine to test F10 key on non multitasking games, maybe it will not work with the code above because it is working on OS level, if i can get a method to simulate the key press at hardware level working with raw key codes, maybe i can make it work. Correct me if i'm wrong...
-
@balrogsoft
You are wrong.
Testing for keypress != generating fake keypresses.
if i can get a method to simulate the key press at hardware level working with raw key codes, maybe i can make it work.
This is not possible. The only way to do this via software would be to patch all the keyboard routines and spoof fake keyboard events.
-
Modifying non-OS friendly games to insert fake keys into their input queue would require as much effort as just adding four player adaptor support directly into the game code.
-
The method above use input.device to send a key event, then it will depend on how the game capture keyboard events, if it use a system friendly method to capture the keyboard, and it isn't multitask, it will work?
-
This would only work of the game uses input.device...
--
moto
-
The method above use input.device to send a key event, then it will depend on how the game capture keyboard events, if it use a system friendly method to capture the keyboard, and it isn't multitask, it will work?
Correct. Any OS friendly apps will capture these events.
This includes:
- input handlers with input.device
- intuition.library IDCMP messages (IDCMP_RAWKEY and IDCMP_VANILLAKEY).
- anything else deriving their keys from the two above
It doesn't include:
- lowlevel.library GetKey() and QueryKeys() (unfortunately GetKey() peeks hw directly and QueryKeys() reads the matrix from keyboard.device directly). These two lowlevel.library functions can be patched, however.
- games/apps reading the keyboard hw directly
-
I guess you could patch the Keyboard interrupt. A lot of non-multitasking games probably still use this, as it's the best fool-proof way to get keyboard input. But of course that is only triggered when a key is actually pressed. Any other interrupt, e.g. vertical blank, is liable to be turned off or replaced.
It also means writing to the CIA Serial Data Register ($BFEC01) directly, not sure how well that would work, if at all.
-
@Tricky
Can't see how that would help really, as you indeed can't spoof the CIA SDR values. Triggering the int would be possible by just setting the proper intreq flag (iirc, it has been a long long time ;-)).
-
@Piru
You can write to the SDR, and it will stay as written until the next keypress. (I just tried it.) So doing that before exiting the interrupt should spoof a keypress.
However, how does one invoke the interrupt? Of course we can set the Intreq bit, but where do we set it from? If we set it from the keyboard interrupt server, the computer will never execute anything other than that interrupt!
-
Hm hm, I was fairly sure writing SDR would not work, since I tried to play with this years ago. Ohwell.
However, how does one invoke the interrupt? Of course we can set the Intreq bit, but where do we set it from?
From the part generating the false events, naturally (joystick movement are turned into key presses and releases).
-
Simply writing to SDR won't generate a keypress, of course. You'd need to trigger the interrupt as well. Which may well overwrite the SDR anyway doing what it does... but if you're writing to it FROM the interrupt, all should be ok. Maybe...
Thing is though, joystick movements don't generate any interrupts, so there would be no way to make them generate the interrupt without changing the code of the non-multitasking program. We could set a vertical blank interrupt to do it, but the game would probably turn it off to set its own.
-
If joystick movements don't generate an interrupt, then how do you check for them?
--
moto
-
motorollin wrote:
If joystick movements don't generate an interrupt, then how do you check for them?
--
moto
You just read directly out of some registers, any time you need to know the state of the joystick. Usually once a frame.
-
So WHDLoad must already be doing this with the keyboard, right? That's how it detects the quit key. Couldn't code be added to poll the keyboard registers, and remap to keyboard events? Which joysticks are checked and which keys the map to could be specified in the tooltypes of the game.
--
moto
-
@motorollin
I don't know how WHDLoad does it, but as mentioned earlier, it's a specific hack for each specific game, not a catch-all solution. Someone must have spent some time figuring it out for each of the games it works on.
There is already code that polls the keyboard registers, that's what the keyboard interrupt does. This code is called when someone presses or releases a key. That's what I'm talking about doing, patching this interrupt (which is part of the OS, not the game) with extra code. But there is nowhere to put code that checks the joystick, other than in that interrupt, or other than actually rewriting the game itself. But if you put it in that interrupt, of course it will only look at the joystick when someone presses a key on the keyboard!
-
I suppose you would have to insert code in to the game to make it check the joystick every frame, and then generate a keyboard interrupt. But as you said, that means re-writing the game.
I less elegant but easier solution may be to use hardware. Maybe something which connects to the keyboard interface but has joystick inputs. The hardware would translate the joystick input in to keyboard events. A passthrough would ensure you can still connect your keyboard.
--
moto
-
@motorollin
I thought about this... it's do-able, but some task... especially if you sometimes need to configure it to use different keys.
It's just a shame 4 player games don't already work with the 4-player adapter, then we wouldn't even need to solve this problem!
-
Some hours offline and i found 2 pages on this topic, thanks to all, i will try to use input device and send system friendly events, i found a device example on blitz basic 2, blitz2 have commands to access AmigaOS devices, but i will take a look on my Amiga Hardware books and read about keyboard interrupts. Thanks to all, very interesting reading.
-
@Tricky
Of course, you would need some way of changing the mappings for different games. Maybe the interface would wait for an unusual key combination (maybe all of the F keys simultaneously), at which point it would enter a programming mode. You would then press the keys on the keyboard (in a set order) which you want to map to up/down/left/right/fire.
You could even have software which has presets for different games, so you just select the game you want from a list, and the software simulates pressing all of the F keys to put the interface in to programming mode, then simulates pressing the correct keys for that game. The application should be controllable by the command line so it can be included in a script when launching the game.
--
moto
-
@motorollin
I don't think you can send signals right back to the keyboard itself. I suspect it only gets back as far as the CIA chip. To add that sort of functionality, you're going to have to start soldering things direct to your motherboard... not a nice concept.
But if you're wiring a couple extra joystick ports on it, of course you could also wire in a special "program" switch. When that switch is on, if you press a joystick control and a key simultaneously it would assign it.
-
Tricky wrote:
@motorollin
I don't think you can send signals right back to the keyboard itself. I suspect it only gets back as far as the CIA chip. To add that sort of functionality, you're going to have to start soldering things direct to your motherboard... not a nice concept.
Good point... simulating a keypress wouldn't be the same as pressing the key (which could be detected by the device).
Tricky wrote:
But if you're wiring a couple extra joystick ports on it, of course you could also wire in a special "program" switch. When that switch is on, if you press a joystick control and a key simultaneously it would assign it.
That would work, but you couldn't automate it through software. Maybe the device could connect to the parallel port and receive its mappings that way.
--
moto
-
motorollin wrote:
Maybe the device could connect to the parallel port and receive its mappings that way.
This is getting very silly now...
-
I less elegant but easier solution may be to use hardware.
hardware solution (http://home.pages.at/mircosoft/Joystick.JPG)
/me runs ;-)
-
A few questions more, as i understand the main problem to use keyboard interrupt is that joystick don't generate a interrupt, when i send an event to keyboard using input.device, it will call keyboard interrupt? And if we put something on the keyboard to have a key continously pressed? then the interrupt will be called, then you can overwrite the interrupt and read joystick, and put the key that we want to simulate. I don't know if it will work... I saw also a note on Amiga hardware reference saying that you can't use $BFEC01 address, that is the serial input connected to keyboard, it says that hardware is using continously.
-
when i send an event to keyboard using input.device, it will call keyboard interrupt?
No. Keyboard interrupt only occurs when actual real physical keys are pressed (or keyboard wants to communicate with the rest of the system for some reason).
input.device IND_WRITEEVENT is purely software, it spoofs an input event that is picked up by all input handlers (including that of intuition.library).