REM An example module to make a click whenever a key is pressed : ON ERROR E$=REPORT$+" at line "+STR$(ERL):OFF:ERROR 0,E$ : DIM code 1024 FOR pass=12 TO 14 STEP 2 REM Note the use of offset assembly is ESSENTIAL when writing modules, otherwise REM the headers won't work. P%=0:O%=code:L%=code+1024 [OPT pass : ; ; Module header comes first... we need to set the offset (P%) to zero so ; that these constants are offsets from the start of the module rather than ; dependent on where they are assembled in memory. ; EQUD 0 ; 'Start' code EQUD initialise EQUD finalise EQUD 0 ; Service call handling code EQUD title EQUD help EQUD command_table .title EQUS "KeyClick":EQUB 0 .help EQUS "KeyClick":EQUB 9:EQUB 9:EQUS "0.01 (02 Feb 1997)":EQUB 0 .syntax_keyclick EQUS "Syntax: *KeyClick [volume]":EQUB 0 .help_keyclick EQUS "This command sets the volume of the key beep, from 1-15. *KeyClick without a number displays the current setting.":EQUB 0 ALIGN : .volume EQUD 8 ; One word used to store volume. Defaults to half. .string_buffer EQUD 0 ; Temporary space for storing a string (see below) : .initialise STMFD R13!,{R14} MOV R0,#&14 ; InsV traps all insertions into buffers ADR R1,insv_claim ; Point to our code MOV R2,#0 ; We don't need this value SWI "XOS_Claim" ; Claim InsV LDMFD R13!,{PC} : .finalise STMFD R13!,{R14} MOV R0,#&14 ADR R1,insv_claim MOV R2,#0 SWI "XOS_Release" ; Release InsV LDMFD R13!,{PC} : .command_table EQUS "KeyClick":EQUB 0:ALIGN ; * command to implement EQUD command_keyclick ; Offset to code EQUB 0 ; Minimum no. of parameters EQUB 0 ; Not used here EQUB 1 ; Maximum no. of parameters EQUB 0 ; Misc. flags, again not used EQUD syntax_keyclick ; Offset to bad syntax message EQUD help_keyclick ; Offset to help message EQUD 0 ; Terminate command table : .command_keyclick STMFD R13!,{R14} ; Entered with R0 > command tail ; and R1 = no. of parameters ; ; First thing to do is to check whether the user has passed any parameters ; to the *KeyClick command. If none are supplied, we just need to display ; the current settings, otherwise jump to the code to set the volume. ; CMP R1,#1 BEQ command_keyclick_set_volume : SWI "OS_WriteS" EQUS "Current volume (range is 0-15): ":EQUB 0:ALIGN LDR R0,volume ; Integer to be converted ADR R1,string_buffer ; Address of buffer MOV R2,#4 ; Size of buffer SWI "OS_ConvertCardinal1" ; Convert number -> string SWI "OS_Write0" ; Write it to the screen SWI "OS_NewLine" B command_keyclick_finish : .command_keyclick_set_volume MOV R1,R0 ; R1 > string to be converted MOV R0,#10 ; R0 = number base SWI "XOS_ReadUnsigned" ; Converts string to a number ; (-ve numbers will cause an error) ; ; If there are any errors, OS_ReadUnsigned will return silently, setting the ; oVerflow flag and making R0 point to an error block. If we exit with ; R0 still pointing to this error block and the overflow flag still set, the OS ; will report the error for us, hence the next instruction. ; BVS command_keyclick_finish : CMP R2,#15 ; Volume must be below 15 BLE volume_in_range SWI "OS_WriteS" EQUS "Volume must be in range 0-15":EQUB 0:ALIGN SWI "OS_NewLine" B command_keyclick_finish .volume_in_range STR R2,volume ; Store new volume .command_keyclick_finish LDMFD R13!,{PC} : .insv_claim ; ; Once claimed, this routine will be called whenever a character is inserted ; into a buffer. The buffer number is passed in R0, and we're only interested ; in the keyboard buffer (0), but there's a flag possibly set in bit 31, so we ; need to test only if the first eight bits are zero. This can be done with a ; TST instruction, which (in this case) ANDs R1 with 255 and reflects the ; results in the status flags, so if zero is reported (Z flag), we can use ; the EQ/NE condition codes to test for it. ; TST R1,#255 MOVNES PC,R14 : STMFD R13!,{R8-R9,R14} : ; ; Now, this piece of code is entered in IRQ mode, which means that trying to ; execute SWIs is a no-no unless we change the processor mode first. See the ; magazine for details. ; MOV R9,PC ORR R8,R9,#3 TEQP R8,#0 MOV R0,R0 : STMFD R13!,{R0-R3,R14} MOV R0,#1 ; In BASIC this is SOUND 1,-volume,&7000,1 LDR R1,volume RSB R1,R1,#0 MOV R2,#&7000 MOV R3,#1 SWI "Sound_Control" LDMFD R13!,{R0-R3,R14} : TEQP R9,#0 MOV R0,R0 ; Restore processor mode : LDMFD R13!,{R8-R9,PC}^ : ]:NEXT REM Save our module out with the correct filetype SYS "OS_File",10,"KeyClick",&FFA,,code,O%