numlangs=3 ;включая graph
keyqueuemax=5
kZ=0 ;яверты
kJ=0 ;йцукен
multikbd=0
kR=1 ;шверты
NkJ=kZ+kR
ukr=1
KEYSCAN
KEYMATRIX
LD HL,tkeymatrixstate
LD BC,#7FFE ;Space=0, cs=35
IN A,(C)
RRA
RRA ;ss
LD A,C
IN A,(#FE)
RLA
AND 3
LD (keymshifts),A ;A0=ss,A1=cs
LD E,0 ;scancode
KEYM0 IN A,(C)
LD (keym0BC),BC
LD (keym0HL),HL
LD C,(HL),(HL),A
XOR C ;C=old state
LD D,A ;D=changes
LD B,5
KEYM1 RR D
jr NC,KEYMnPUT
LD (keym1BC),BC
LD (keym1DE),DE
keymshifts=$+1
LD D,0
;C0=press(1)/release(0)
;E=scancode, D=shiftstate
;D=%00: ext
;D=%01: cs
;D=%10: ss
;D=%11: no shifts
DEC D
LD HL,tkeydecodecs
jr Z,KEYDECODEPASS ;cs+key
DEC D
LD HL,tkeydecodess
JR z,KEYDECODEPASS ;ss+key
DEC D
LD HL,tkeydecode
jr Z,KEYDECODEPASS ;no shifts+key
LD HL,tkeydecodeext ;ext+key
KEYDECODEPASS
LD D,0
ADD HL,DE
ld A,(HL)
CP ssnoshifts ;crucial for autorepeat of ssSpace
jr Z,KEYMPUTSKIP
CP csnoshifts ;csnoshifts keypress can appear in the same frame as cs6 etc and must be ignored
keym_keyrep
LD B,E
CALL NZ,KEYREP ;A=code
;C0=press(1)/release(0)
;B=scancode without shifts
KEYMPUTSKIP
keym1DE=$+1
LD DE,0
keym1BC=$+1
LD BC,0
KEYMnPUT
INC E
RR C
DJNZ KEYM1
keym0HL=$+1
LD HL,0
INC HL
keym0BC=$+1
LD BC,0
RRC B ;next halfrow
jr C,KEYM0
;blowing
ld a,(keyrepcounter)
OR A
RET Z
DEC A
jr Z,KEYREPSEND
KEYREPSETCNT
LD (keyrepcounter),A
RET
;C0=press(1)/release(0)
;A=code
;B=scancode without shifts
KEYREP
IF 1==0
push af
push bc
push de
push hl
ld a,b
add a,'A'
ld c,a
ld b,0
call KEYQUEUEPUT
ld a,(keyrepscancode)
add a,'A'
ld c,a
ld b,0
call KEYQUEUEPUT
pop hl
pop de
pop bc
pop af
ENDIF
RR C ;NC=release
jr C,KEYREPPRESS
;CP/M: if this is "ext" (cs or ext release): if keyrepkey was "ext", then make "ext" keypress (and forget "ext" to avoid "ext, cs" work as ext, ext), else make "csnoshifts" keypress (for AltGr)
cp csss
jr nz,KEYREPRELEASE
keyrepkey=$+1
cp 0
ld a,csnoshifts
LD (keyrepkey),A ;forget "ext" to avoid "ext, cs" work as ext, ext
jr nz,KEYREPSEND
ld a,csss
jr KEYREPSENDA
KEYREPRELEASE
;if the repeated key (without shifts) is released
;then stop key repeat
;or else ignore
LD A,B ;scancode without shifts
keyrepscancode=$+1
SUB -1
RET NZ
;XOR A
JR KEYREPSETCNT
KEYREPPRESS
cp cssspress ;=csss
jr nz,KEYREPPRESSncsss
keyrepcounter=$+1
LD d,0
inc d
dec d
ret nz ;ext keypress, but another key is already pressed - ignore ext ;to filter out ext keypress in the same frame as ext+3 keypress (ss+PgUp pressed)
;z
KEYREPPRESSncsss
LD (keyrepkey),A
ret z ;no "ext" keypress, only release
SUB cs1;'1'-32
CP 2
jr C,KEYREPSEND ;no autorep for cs1..2
LD A,B ;scancode without shifts
LD (keyrepscancode),A
LD A,14;10
LD (keyrepcounter),A
KEYREPSEND
ld a,(keyrepkey)
KEYREPSENDA
;A = code ;[(cs+1 was encoded as '1'-32)]
;csnoshifts means CS release
;idle: cs1..2 start, csnoshifts skip, others pass by
;working: cs0..9 add, others end (1,2 add cs0)
KEYALTGR
altgrN=$+1
LD BC,#100 ;C=AltGr code (0=idle), B=1 (codes)
ld e,a ;current key
sub cs0;'0'-32
jr z,KEYALTGRcs0
SUB cs1-1 -cs0
KEYALTGRcs0
LD D,A ;0..9 in good case
INC C
DEC C
jr Z,KEYALTGR_IDLE
CP 10
LD A,C
jr NC,KEYALTGRPUT ;stop AltGr (csnoshifts or wrong key) ;a=final code
ADD A,A
ADD A,A
ADD A,C
ADD A,A ;D*10
ADD A,D
KEYALTGRN
LD (altgrN),A
RET
KEYALTGR_IDLE
;A=1..2 in good case
DEC A
CP 2 ;CY=1: cs1/cs2
INC A
jr C,KEYALTGRN ;start AltGr
ld a,e ;current key
jr KEYALTGRPUT_NO1_2 ;for passing extA(=1),extB(=2)
KEYALTGRPUT
;cs release gives final code here (=1 or 2 for single keypress of cs1 or cs2)
cp 3
jr nc,$+5
add a,cs1-1
KEYALTGRPUT_NO1_2
inc b ;control keys
or a;CP csnoshifts
RET Z ;avoid NOKEY
LD C,A
XOR A
LD (altgrN),A ;idle
;BC=code (B=2 => might be control code) (B=1 means AltGr symbol, for KEYLANG passby)
KEYSWITCH
DEC B
jr Z,KEYSWPASS ;B=0 ;AltGr symbol, for KEYLANG passby
LD A,C
;push af
;push bc
;ld bc,'a'
;ld c,a
;call KEYQUEUEPUT
;pop bc
;pop af
keyswstate=$+1
LD HL,#100 ;H=язык=1..numlangs (H=numlangs при graph)
;L0=CapsLock
CP cs2
jr Z,KEYSWCAPSLOCK
CP cs1
jr Z,KEYSWLANG
CP ext1
jr NZ,KEYSWPASS
KEYSWGRAPH
LD A,H
LD H,numlangs
CP H ;graph уже включен?
jr NZ,KEYSWOK ;нет - включаем, иначе DEC H
KEYSWLANG
DEC H
jr NZ,$+4
LD H,numlangs-1
DEC L
KEYSWCAPSLOCK
INC L
KEYSWOK
LD (keyswstate),HL
;pass key to make possible to redraw blinking cursor
KEYSWPASS
;BC=code (B=0 means AltGr symbol, for KEYLANG passby) (B=1 for usual keys)
KEYLANG
INC B
DEC B
jr Z,KEYLANGPASS ;B=0: symbol from ALTGR
;B=1
;CALL KEYQUEUEPUT ;BC=code
ld (keyqueueput_codenolang),bc
KEYLANG_REPEAT
LD A,C
LD (keylangcode),A
sub ext1 ;how it worked in ACEdit without this check?
jr z,KEYLANGPASS_A ;B=1 (control key) ;a=0=NOKEY => c
sub cs1-ext1 ;how it worked in ACEdit without this check?
jr z,KEYLANGPASS_A ;B=1 (control key) ;a=0=NOKEY => c
sub cs2-cs1 ;how it worked in ACEdit without this check?
jr z,KEYLANGPASS_A ;B=1 (control key) ;a=0=NOKEY => c
SUB 0xff&(32-cs2)
CP 95
jr NC,KEYLANGPASS ;B=1 (control key)
rustrdisp=$+1
LD DE,0 ;D=0
INC E
DEC E
jr NZ,KEYLANG_SHV2 ;second key of combination?
keylangcode=$+1
LD BC,0 ;B=0, C=code
LD DE,(keyswstate)
;BC=code
DEC D
jr Z,KEYL_ENG ;B=0
DEC D
jr NZ,KEYL_GRAPH ;B=0
KEYL_RUSTR
;B=0
IF multikbd
kmode=$+1
LD A,1
CP kR
jr Z,KEYL_SHVERTY
CALL RERUS
JR KEYLANGPUT ;B=0
KEYL_SHVERTY
ENDIF
LD A,C
CP 64
jr C,KEYLANGPUT ;B=0
LD HL,tkeyl_rustr
ADD HL,BC
LD C,(HL)
LD A,C
CP 64
jr NC,KEYLANGPUT ;B=0
;LD (rustrdisp),BC ;B=0
;LD A,C
LD (rustrdisp),A
;RET
ld c,b ;b=0 ;put keylang=0 with current keynolang
jr KEYLANGQ
KEYLANG_SHV2
LD (rustrNEW),BC
LD A,C;(rustrNEW)
;LD (rustrNEW),A
;rustrdisp=$+1
;LD DE,0 ;D=0
LD HL,tkeyl_rustrc
ADD HL,DE
LD C,(HL) ;len
LD B,D ;=0
INC HL
LD E,C
CPIR
LD C,E ;B=0
ADD HL,BC
jr Z,KEYLANGCOMBO ;combination entered (such as qq)
;no such combination - take symbol #len
LD A,(HL)
CALL case
LD C,A
CALL KEYQUEUEPUT ;B=0
rustrNEW=$+1
LD BC,0 ;B=0
XOR A
LD (rustrdisp),A
ld h,a
ld l,a
;ld (keyqueueput_codenolang),hl ;no keynolang for 2nd symbol
JR KEYLANG_REPEAT ;doubling and recoding the 2nd symbol
KEYL_GRAPH
;B=0
;'0' -> 0030
;'1' -> 0031
;'2' -> 0032
;'3' -> 0033
;'4' -> 0034
;'a' -> 0061
;do "case" first!!!
LD A,C
CALL case
LD C,A
LD HL,tkeyl_graph
ADD HL,BC
LD C,(HL)
jr KEYLANGPASS
KEYLANGCOMBO
DEC HL
LD C,(HL)
KEYL_ENG ;B=0
KEYLANGPUT ;B=0
LD A,C
CALL case
KEYLANGPASS_A
LD C,A
KEYLANGPASS
XOR A
LD (rustrdisp),A
KEYLANGQ
;BC=code (B=1 => control key)
KEYQUEUEPUT
keyqueueN=$+1
LD A,0 ;decreased AFTER reading from queue
CP keyqueuemax
RET Z ;no room
INC A
LD (keyqueueN),A
;ALTGR codes: b=0, c=0..255
;letters: b=0, c>=32
;control codes: b=1, c=0..31, #bx, #cx, #dx, #fx
;result: TODO b=1, c=#8x, #9x for ALTGR codes 0..31???
keyqueuehead=$+1
LD HL,tkeyqueue
LD (HL),C
INC HL
LD (HL),B ;B=0: letter, B=1: control key
CALL KEYQUEUEINCHL
keyqueueput_codenolang=$+1
ld bc,0
LD (HL),C
INC HL
LD (HL),B ;B=0: symbol from ALTGR, B=1: other keys
CALL KEYQUEUEINCHL
LD (keyqueuehead),HL
RET
tkeydecodeext
DB key_extspace,ssnoshifts,extM,extN,extB
DB key_extenter,extL,extK,extJ,extH
DB extP,extO,extI,extU,extY
DB ext0,ext9,ext8,ext7,ext6
DB ext1,ext2,ext3,ext4,ext5
DB extQ,extW,extE,extR,extT
DB extA,extS,extD,extF,extG
DB cssspress,extZ,extX,extC,extV
tkeydecode
DB " ",ssnoshifts,"mnb"
DB key_enter,"lkjh"
DB "poiuy"
DB "09876"
DB "12345"
DB "qwert"
DB "asdfg"
DB csss,"zxcv"
tkeydecodecs
DB key_esc,ssnoshifts,"MNB"
DB key_csenter,"LKJH"
DB "POIUY"
;DB '0'-32,'9'-32,'8'-32,'7'-32,'6'-32
;DB '1'-32,'2'-32,'3'-32,'4'-32,'5'-32
db cs0,cs9,cs8,cs7,cs6
db cs1,cs2,cs3,cs4,cs5
DB "QWERT"
DB "ASDFG"
DB csnoshifts,"ZXCV"
tkeydecodess
DB key_ssspace,ssnoshifts,".,*"
DB ssnoshifts,"=+-^"
DB 34,";",ssI,"]["
DB "_)('&"
DB "!@#$%"
DB ssQ,ssW,ssE,"<>"
DB "~|",#5c,"{}"
DB csss,":`?/" ;in fact csss keypress is taken from tkeydecodeext, csss release from tkeydecodecs
tkeymatrixstate
DS 8,#FF ;initially nothing pressed
tkeyl_graph=$-32
DB 32,14,34,16,17,18,19,20,"()*+,-./"
DB 12,1,2,3,4,5,6,7,8,11,":;єўЄ?"
DB 15,"╠╧╝╣╗╞╪╡▄▀■¤№╛▌▐╔╒╬╤█╘╦╩╕╚[",#5c,"]^_"
DB "`├╨┘┤┐╟╫╢─░▒▓√╜║═┌╓┼╥│╙┬┴╖└{|}~"
tkeyl_rustr=$-64
DB "@АБ",rustrCdisp
DB "ДЕФГ",rustrHdisp,"И",rustrJdisp
DB "КЛМНОП",rustrQdisp
DB "РСТУЖВЬЫЗ[",#5c,"]^_"
DB "`аб",rustrcdisp
DB "дефг",rustrhdisp,"и",rustrjdisp
DB "клмноп",rustrqdisp
DB "рстужвьыз{|}~"
tkeyl_rustrc=$-1 ;to avoid zero displacements
rustrhdisp=$-tkeyl_rustrc
DB 1,"h","э","х"
rustrHdisp=$-tkeyl_rustrc
DB 1,"H","Э","Х"
rustrqdisp=$-tkeyl_rustrc
DB 1,"q","щ","ш"
rustrQdisp=$-tkeyl_rustrc
DB 1,"Q","Щ","Ш"
rustrcdisp=$-tkeyl_rustrc
IF ukr
DB 2,"gc",#F3,"ц","ч"
ELSE
DB 1,"c","ц","ч"
ENDIF
rustrCdisp=$-tkeyl_rustrc
IF ukr
DB 2,"GC",#F2,"Ц","Ч"
ELSE
DB 1,"C","Ц","Ч"
ENDIF
rustrjdisp=$-tkeyl_rustrc
IF ukr
DB 7,"eyiaouj",#F5,#F7,#F9,"яёюъ","й"
ELSE
DB 4,"aouj","яёюъ","й"
ENDIF
rustrJdisp=$-tkeyl_rustrc
DISPLAY $-tkeyl_rustrc,"<64"
IF ukr
DB 7,"EYIAOUJ",#F4,#F6,#F8,"ЯЁЮЪ","Й"
ELSE
DB 4,"AOUJ","ЯЁЮЪ","Й"
ENDIF
IF kZ
rt
DB "ЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧъ"
ENDIF
IF kJ
rtjcuk
DB "@ФИСВУАПРШОЛДЬТЩЗЙКЫЕГМЦЧНЯ[",#5c,"]^_"
ENDIF
RERUS
;in: C=code (32..126), A=kmode
;out: C=code
;keeps B
LD D,C ;code
IF kZ
LD HL,rt
ENDIF
IF kJ
IF multikbd
CP NkJ
jr NZ,rERUSnJCUK
ENDIF
LD HL,rtjcuk
LD A,D ;code
LD C,'б'
CP '!'
RET Z
LD C,'ж'
CP '@'
RET Z
LD C,'х'
SUB '#'
RET Z
LD C,'э'
DEC A ;'$'
RET Z
INC C ;'ю'
DEC A ;'%'
RET Z
rERUSnJCUK ;
ENDIF
LD A,D ;code (32..126)
LD C,'ё'
CP '&'
RET Z
LD C,D
BIT 6,D ;code
RET Z ;code <64 (not letter) - return old code
;A=code (64..126)
AND 31
ADD A,L
LD L,A
jr NC,$+3
INC H
LD A,(HL) ;capital Russian
BIT 7,A
RET Z ;not a letter in the table - return old code
LD C,A ;capital Russian
BIT 5,D ;code
RET Z ;C contained capital letter, return capital
CALL RECAP
LD C,A ;small Russian
RET
CHECKCAPSLOCK
PUSH HL
LD HL,keyswstate
BIT 0,(HL)
POP HL
RET
case
CALL CHECKCAPSLOCK
RET Z
RECAP
CP 0xf2;je'Є'
RET NC
XOR 1
CP 0xf0;jo'Ё'
RET NC
XOR 1
CP 0xe0;'р'
jr NC,BECAPRL
CP 0xb0;'-'
RET NC
CP 0xa0;'а'
jr NC,BECAPOK
CP 0x90;'Р'
jr NC,BECAPRL
CP 0x80;'А'
jr NC,BECAPOK
CP '@'
RET Z
CP '_'
RET Z
CP 'A'
RET C
CP '{'
RET NC
CP '['
jr C,$+5
CP 'a'
RET C
BECAPOK XOR 80
BECAPRL XOR #70
RET
KEYQUEUEINCHL
INC HL
LD A,L
CP tkeyqueueend&0xff
RET NZ
LD HL,tkeyqueue
RET
tkeyqueue
DS 4*keyqueuemax
tkeyqueueend
PEEKKEY
LD A,(keyqueueN)
OR A
ld h,a
RET Z ;a=NOKEY, h=0
LD HL,(keyqueuetail)
LD a,(HL)
INC HL
LD h,(HL)
ret
GETKEY
;out: ha=key (NOKEY=none), bc=keynolang keeps de,l
;H0=1 for control codes, H0=0 for symbols
;TODO уфх-Єю т H фюсртшЄ№ сшЄ√ ЁхушёЄЁр ъыртшрЄєЁ√
LD A,(keyqueueN)
OR A
ld h,a
ld b,a
ld c,a
RET Z ;a=NOKEY, h=0, bc=0
PUSH de
PUSH HL
keyqueuetail=$+1
LD HL,tkeyqueue
;2 bytes with language
;2 bytes without language
LD e,(HL)
INC HL
LD d,(HL) ;keylang
CALL KEYQUEUEINCHL
LD c,(HL)
INC HL
LD b,(HL) ;keynolang
CALL KEYQUEUEINCHL
LD (keyqueuetail),HL
LD HL,keyqueueN
DEC (HL) ;atomic!!! (or we can miss keyqueueN increase)
;after reading!!! (or it might be overwritten while reading)
POP HL
ld h,d ;keylang HSB
ld a,e ;keylang LSB
pop de
RET
KEY_PUTREDRAW
;ўшёЄшь юўхЁхф№ ъыртшрЄєЁ√
call GETKEY
or c
jr nz,KEY_PUTREDRAW
;ъырф╕ь ъэюяъє яхЁхЁшёютъш, хёыш х╕ эхЄ т юўхЁхфш
;;ld a,key_redraw
;;ld (curkey),a
;call PEEKKEY ;ld a,(curkey) ;TODO ёьюЄЁхЄ№ уюыютє юўхЁхфш, р эх їтюёЄ
;cp key_redraw
;ret z
ld bc,key_redraw
ld (keyqueueput_codenolang),bc
jp KEYQUEUEPUT ;хёыш яхЁхъы■ўшышё№ эр эхръЄштэє■ чрфрўє, Єю эхъюьє яЁюўшЄрЄ№ ъюф!!