17 January 2020, 20:59 | #1 |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Detect a single keystroke in the Shell window
Hi,
I've got a little problem on how to detect a keystroke in the Shell window in a system friendly way. I wrote a little Shell-command which informs the user to press the keys "y" to admit or "n" to reject an action. I know from many pure Shell commands that only a key is pressed and the program proceeds. Pressing the return key is not necessary. So they don't use the Input() command of the dos.library. I want to code such a routine in assembler. But how do I detect such a keystroke in the Shell window? Via the IDCMP flags VANILLAKEY or RAWKEY (which won't be set automatically in the Shell window structure I guess), via the keybord.device or the CON:-device directly? I know that I have to create a message port (for keyboard/CON device) to get a signal what I could use for the Wait() function. I also know that the signal bit needed for this function is derived from mp_SigBit of the port. Does someone have a little code section which shows how to wait for the keys "y" and "n" pressed in the Shell window? Thanks, Dissident |
17 January 2020, 21:43 | #2 | ||
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,214
|
Quote:
Quote:
https://wiki.amigaos.net/wiki/AmigaDOS_Packets for more details. This packet tells the con-handler to deliver keystrokes directly, i.e. unbuffered, without line buffering. Read the key, with Read(), then switch the con-handler back to con-mode. To send the packet, you need to get the message port from the file handle you received from Input(). For this, convert the BPTR from Input() into a pointer by shifting it left by 2 bits, then read the fh_Type member of the struct FileHandle, see again <dos/dosextens.h> for the structure. ACTION_SCREEN_MODE takes one parameter that controls line buffering on or off. If I recall correctly, the parameter is 0 for line buffering on, and 1 for line buffering off. (And 2, from 3.2 on, for the medium mode used by the shell). No, you are on the wrong track. The only message port you need is that of the process your program is running as, and this already exists. No IDCMP, no console.device. The console.device is already in use by the con-handler, and it does not have an IDCMP either. |
||
17 January 2020, 22:20 | #4 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
Funny, I was searching old usenet yesterday for something like that.
I came across this one https://github.com/alexalkis/sillych...03ff9356ac54dd It's in C, but should give the general idea. Looks 1.3 compatible. I haven't found the time to test it yet, though. |
17 January 2020, 22:58 | #5 | |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Quote:
Many thanks for your detailed answer, Thomas. I know the "RAW-mode" from using RAW-windows. Switching the console to the "RAW-mode" is a very smart trick. I guess this method also works on pre- OS2.x systems. This solution explains the whole behaviour of the CON-window which acts like a RAW-window. I will try to write a routine based on your great explanation. |
|
17 January 2020, 23:01 | #6 | |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Quote:
Fine, a good hint, mark_k. I will use this DOS function in my alternative 68020/OS2.x version of my little tool. |
|
17 January 2020, 23:03 | #7 | |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Quote:
Thanks for sharing the link, alkis. I will check it. |
|
19 January 2020, 17:14 | #8 | |
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Quote:
Sorry, my knowledge about C is very miserable. I don't understand these lines: Code:
register struct Process * proc; register struct StandardPacket * packet; register LONG res1; proc = (struct Process *)FindTask(NULL); if (packet = (struct StandardPacket *)AllocMem( sizeof(struct StandardPacket), MEMF_CLEAR | MEMF_PUBLIC) ) { packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt); packet->sp_Pkt.dp_Link = & packet->sp_Msg; packet->sp_Pkt.dp_Port = & proc->pr_MsgPort; packet->sp_Pkt.dp_Type = action; Code:
struct Message { struct Node mn_Node; struct MsgPort *mn_ReplyPort; /* message reply port */ UWORD mn_Length; /* total message length, in bytes */ /* (include the size of the Message */ /* structure in the length) */ Only the entries "sp_link"," dp_port" and "dp_type" of the packet structure are initialized. And what does this line below mean? Code:
packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt); The only thing I've understood is how to get the pointer to the message port of the CON device. There are two ways: One way is via the input-handle like Thomas told me: Code:
CALLDOS Input move.l d0,input_handle(a3) ;Save handle beq input_handle_error ;If NULL -> skip move.l d0,a0 ;BPTR add.l a0,a0 ;*4 = CPTR add.l a0,a0 move.l fh_type(a0),d0 ;Get Message-Port for PutMsg() beq port_error ;If NULL -> skip move.l d0,a4 ;Get pointer to Message-Port structure Code:
sub.l a1,a1 ;NULL = Search for own Task CALLEXEC FindTask ;Get pointer to own Task-structure/Process structure tst.l d0 beq no_task_found ;If NULL -> skip move.l d0,a0 ;Get pointer to Task/Process move.b LN_TYPE(a0),d0 ;Get type cmp.b #NT_PROCESS,d0 ;DOS process ? bne no_dos_process ;No -> skip move.l pr_ConsoleTask(a0),a4 ;Get pointer to message port structure |
|
19 January 2020, 20:56 | #9 | |||||
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,214
|
Quote:
Quote:
Quote:
Well, this is the beauty of Tripos: It was an operating system of its own, and all what happend when "Caos" did not become ready was that our friendly developers used an enourmous amount of hot-glue, duct-tape and chewing gum to fit the Tripos core - which we nowadays call the dos.library - on top of the already existing multitasking core, which we call the exec.library. What you see here is exactly this type of "hot glue": Message passing requires messages, but Tripos does not use messages. It uses packets. So the message is used to transport the packet as exec uses the latter, but tripos depends on the former. There is no pointer to in an exec message to point to the message, so Tripos hijacks the name pointer, which is then not a name at all. Also, the handler you send the packet to - here the console - was part of tripos, and it did not use the exec message at all. Instead, Tripos has its own way of replying messages, namely to use pkt->dp_Port as reply port, and "PutMsg" the packet back there. mn_ReplyPort is not used at all. Junk, I know, but this is another layer of hotglue, ducktape... you name it. Quote:
Quote:
Thus, there are actually two structures, the packet and the message, that are crosswise linked to each other, one over the "dp_Link" pointer, the other by hijacking mn_Node.ln_Name. As said... layers of hot glue, duct tape and chewing gum. |
|||||
19 January 2020, 21:18 | #10 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
Code:
incdir "/opt/amiga/gcc6/m68k-amigaos/ndk-include" include dos/dosextens.i include lvo/exec_lib.i include lvo/dos_lib.i CALL MACRO jsr _LVO\1(a6) ENDM move.l $4.w,a6 move.l a6,_SysBase lea.l DOSNAME,a1 moveq.l #0,d0 CALL OpenLibrary move.l d0,_DOSBase beq errorNoDOS moveq.l #-1,d0 bsr @set_screen_mode move.l _DOSBase,a6 CALL Input move.l d0,stdInput move.l d0,d1 ;should guard for 0 here...too lazy now move.l #15*1000000,d2 CALL WaitForChar tst.l d0 beq nochar move.l stdInput,d1 move.l #thechar,d2 moveq.l #1,D3 CALL Read CALL Output move.l d0,d1 move.l #msg,d2 move.l #msgend-msg,d3 CALL Write nochar: moveq.l #0,d0 bsr @set_screen_mode move.l _SysBase,a6 move.l _DOSBase,a1 CALL CloseLibrary moveq.l #42,d0 rts errorNoDOS: moveq.l #20,d0 rts @set_screen_mode: move.l d0,-(sp) bsr _set_screen_mode addq.l #4,sp rts _set_screen_mode: link.w a5,#-28 move.l a6,-(sp) move.l d2,-(sp) move.l (8,a5),d2 sub.l a1,a1 move.l _SysBase,a6 CALL FindTask move.l d0,a0 move.l (164,a0),d0 beq .L1 ext.l d2 move.l d2,(-28,a5) move.l d0,-(sp) pea (-28,a5) pea 994.w bsr _send_packet moveq #1,d0 .L1: move.l (-36,a5),d2 move.l (-32,a5),a6 unlk a5 rts _send_packet: link.w a5,#-20 movem.l a6/a4/a3/a2/d2,-(sp) move.l (12,a5),d2 sub.l a1,a1 move.l _SysBase,a6 CALL FindTask move.l d0,a3 moveq #68,d0 move.l #65537,d1 CALL AllocMem move.l d0,a2 tst.l d0 beq .L5 lea (20,a2),a0 move.l a0,(10,a2) move.l d0,(20,a2) lea (92,a3),a4 move.l a4,(24,a2) move.l (8,a5),(28,a2) tst.l d2 beq .L6 move.l d2,a0 moveq #28,d0 lea (40,a2),a1 CALL CopyMem .L6: move.l a2,a1 move.l (16,a5),a0 CALL PutMsg move.l (180,a3),a1 move.l a1,d0 beq .L7 lea (-20,a5),a0 jsr (a1) .L8: move.l (172,a3),d0 lsl.l #2,d0 move.l d0,a0 move.l (36,a2),(a0) move.l (32,a2),a3 move.l _SysBase,a6 moveq #68,d0 move.l a2,a1 CALL FreeMem .L4: move.l a3,d0 movem.l (-40,a5),d2/a2/a3/a4/a6 unlk a5 rts .L7: move.l a4,a0 move.l _SysBase,a6 CALL WaitPort move.l a4,a0 CALL GetMsg bra .L8 .L5: move.l (172,a3),d0 lsl.l #2,d0 move.l d0,a0 moveq #103,d1 move.l d1,(a0) move.l a2,a3 bra .L4 section data _SysBase: dc.l 0 _DOSBase: dc.l 0 stdInput: dc.l 0 DOSNAME: dc.b "dos.library",0 msg: dc.b "You pressed " thechar: dc.b " " dc.b "\n" msgend: Assemble with: (you need to change incdir path) vasmm68k_mot -esc -Fhunkexe -kick1hunks consoleraw.s -o craw Lightly tested on A500. Looks like it works. |
19 January 2020, 22:54 | #11 | |
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,214
|
Quote:
There is no need to WaitForChar() if your task attempts to block anyhow. Also, please use the Os includes instead of using absolute offsets. As a side remark, it is not necessary to allocate a standard packet. It can easily sit on the stack. |
|
20 January 2020, 02:25 | #12 | |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
Quote:
PS: https://franke.ms/cex/z/I0smeH Last edited by alkis; 20 January 2020 at 03:01. Reason: added the link to compiler explorer |
|
21 January 2020, 19:21 | #13 | |||
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Quote:
con-mode = 0 raw-mode = 1 or -1 Quote:
1) Packet sending via the file input handler 2) Packet sending via the console handler Quote:
The package sending could be done this way: Code:
; Routine Set-Screen-Mode ; d0 ... Argument for Packet "ACTION_SCREEN_MODE": 0="con-mode" -1="raw-mode" ; d4 ... Pointer to handler Message-Port ; a2 ... Pointer to process Reply-Port CNOP 0,4 set_screen_mode ; ** Message structure init ** lea packet_struc(pc),a1 ;Pointer to Message structure lea sp_Pkt(a1),a0 move.l a0,LN_NAME(a1) ;Save pointer to Packet structure ; ** Packet strcture init ** move.l a1,mn_size+dp_link(a1) ;Save pointer to Message structure move.l a2,mn_size+dp_port(a1) ;Save pointer to Reply Port move.l #ACTION_SCREEN_MODE,mn_size+dp_type(a1) ;Save Packet type move.l d0,mn_size+dp_arg1(a1) ;Save Packet argument ; ** Send packet to console handler or input file handler ** send_packet move.l d4,a0 ;Pointer to handler Message Port CALLEXEC PutMsg move.l a2,a0 ;Pointer to process Reply Port CALLLIBS WaitPort move.l a2,a0 ;Pointer to process Reply Port CALLLIBQ GetMsg For all of you who want to get information from the horse's mouth about DOS internals and in this case about dos packets starting with page 395): https://archive.org/details/1991-bak...-manual-3rd-ed The funny thing is that I knew this book before, but without hints I wouldn't discovered to use dos packets to solve my problem and that everything is explained in this book. And last but not least a big thank you to you all, Thomas Richter, alkis & mark_k As always it was a pleasure to get some great support and learn new things about the programming of the OS. Last edited by dissident; 21 January 2020 at 20:34. |
|||
21 January 2020, 21:17 | #14 | ||||
Registered User
Join Date: Jan 2019
Location: Germany
Posts: 3,214
|
Quote:
Quote:
Quote:
Quote:
|
||||
21 January 2020, 22:05 | #15 | ||||
Registered User
Join Date: Sep 2015
Location: Germany
Posts: 256
|
Quote:
I can tell you that I will use the first option, sending the Packet via the file input() handler in my shell tool. Quote:
Yes you are right, but in all other cases without any wait loop, assembler is shorter and faster. Maybe it has something to do with the fact that I normally write fx-routines for demos where every cycle counts. Quote:
Yes, it was a software failure to be precise. Thanks for the explanation. Quote:
Yes, the "Guru Book" is hard to get, but there shall be spread text files of it. |
||||
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Clear background color for Shell window- Shell-StartUp | fc.studio | support.Apps | 13 | 25 March 2022 18:52 |
Start script without opening a Shell window | Joel_w | support.Apps | 6 | 01 February 2019 16:56 |
Trying the get bold, italic and coloured text out to the shell window. | chocsplease | Coders. C/C++ | 16 | 22 June 2017 14:58 |
Closing current Shell window programmatically? | tygre | Coders. General | 5 | 06 September 2015 06:24 |
Snapshot Amiga Shell window? | TenLeftFingers | support.Apps | 3 | 15 June 2015 16:38 |
|
|