1. Multi-keyread routine

Here's an extremely useful library routine for reading the keyboard.

It is used just like get_key(), except that it's called get_keys(),
it returns a sequence instead of an atom, and the values returned are
scan codes, instead of ASCII codes.

The advantage is that the routine will recognize multiple keypresses
at the same time, and return them in one sequence.
Also, there is no repeat delay, instead the code is returned constantly
until the key is released.

Finally, the routine is also some 10-20 times faster than get_key()

Regards,
                Michael Bolin

------------------------------------ start keyread.e
include machine.e

atom d_interrupt_ad,e_interrupt_ad

procedure disable_interrupts()
    call(d_interrupt_ad)
end procedure

procedure enable_interrupts()
    call(e_interrupt_ad)
end procedure

d_interrupt_ad=allocate(2)
e_interrupt_ad=allocate(2)
if d_interrupt_ad<1 or e_interrupt_ad<1 then
    puts(1,"Could not allocate memory!")
    abort(1)
end if

poke(d_interrupt_ad,{#FA,#C3})      -- cli - ret
poke(e_interrupt_ad,{#FB,#C3})      -- sti - ret

sequence usual_address
atom keyboard_address,keyb_point
atom code_segment,segment,key_buffer

segment=allocate(4)
lock_memory(segment,4)

key_buffer=allocate(1024)
lock_memory(key_buffer,1024)

keyb_point=allocate(4)
lock_memory(keyb_point,4)
poke(keyb_point,{0,0,0,0})          -- offset into keyboard buffer

sequence save_segment_code
save_segment_code = {
    #53,   -- push ebx
    #0E,   -- push cs   or #1E push ds -- only a 16-bit value
    #5B,   -- pop ebx
    #89, #1D} & int_to_bytes(segment) & -- mov segment, ebx
    {#5B,   -- pop ebx
    #C3}    -- ret

atom save_segment
save_segment = allocate(length(save_segment_code))
poke(save_segment, save_segment_code)
call(save_segment) -- save code segment

code_segment = bytes_to_int(peek({segment,4}))

poke(save_segment+1, #1E)
call(save_segment) -- save data segment

usual_address = get_vector(9)

sequence keyboard_code
keyboard_code={#1E,                         -- push ds
               #60,                         -- pushad
               #BB} & peek({segment,4}) &   -- mov ebx, data segment value
               {#53,                        -- push ebx
               #1F,                         -- pop ds
               #BA,#60,00,00,00,            -- mov edx,#60
               #EC,                         -- in al,edx
               #BE} & int_to_bytes(keyb_point) & -- mov esi,keybuffer offset
               {#8B,#2E} &                  -- mov ebp,[esi]
               #BE & int_to_bytes(key_buffer) & -- mov esi,keybuffer
               {#88,#04,#2E} &              -- mov [esi+ebp],al
               #BE & int_to_bytes(keyb_point) & -- move esi,keybuffer offset
               {#45,                        -- inc ebp
               #81,#E5,255,3,0,0,           -- and ebp,255
               #89,#2E,                     -- mov [esi],ebp
              #E4,#61,        -- in al,0x61
                         #0C,#82,        -- or al,0x82
              #E6,#61,        -- out 0x61,al
              #24,#7F,        -- and al,0x7f
              #E6,#61,        -- out 0x61,al
              #B0,#20,        -- mov al,0x20
              #E6,#20,        -- out 0x20,al
              #61,                         -- popad
              #1F,                         -- popds

           #EA}

           &int_to_bytes(usual_address[2])&
           and_bits(usual_address[1],255) & floor(usual_address[1]/256)


keyboard_address=allocate(length(keyboard_code))

poke(keyboard_address,keyboard_code)


poke(key_buffer,repeat(0,1024))
set_vector(9,{code_segment,keyboard_address})

sequence pressed_keys
sequence two_longs,two_codes

pressed_keys={}

           75,203,80,208,72,200,73,201,71,199,82,210}
           28+256,28+384,56+256,56+384,29+256,29+384,333,333+128,
           331,331+128,336,336+128,328,328+128,329,329+128,327,
           327+128,338,338+128}

sequence old_codes
old_codes={}
global function get_keys()
    -- Returns a sequence of keys currently pressed
    sequence codes,slice
    integer offset,place,key,code,pos

    disable_interrupts()
    offset=peek(keyb_point)
    poke(1052,peek(1050))           -- Clear keyboard buffer
    if offset=0 then
        enable_interrupts()
        return pressed_keys
    end if
    poke(keyb_point,0)
    codes=old_codes & peek({key_buffer,offset})
    enable_interrupts()
    place=1
    while place<=length(codes) do
        code=codes[place]
        if code=224 then
            if length(codes)-place=0 then
                exit                            -- If not enough codes in buffer
            end if
            pos=find(codes[place+1],two_longs)
            if pos then
                key=two_codes[pos]
                place=place+1
            else
                key=0
            end if
        elsif code=225 then                         -- Ignore pause key
            key=0
            if length(codes)-place>=5 then
                place=place+4
            else
                exit
            end if
        else
            key=code
        end if
        if key then                 -- Insert or remove key from pressed list
            if and_bits(key,128)=128 then
                pos=find(key-128,pressed_keys)
                if pos then
                    pressed_keys=pressed_keys[1..pos-1] &
                        pressed_keys[pos+1..length(pressed_keys)]
                end if
            else
                pos=find(key,pressed_keys)
                if pos=0 then
                    pressed_keys=append(pressed_keys,key)
                end if
            end if
            place=place+1
        else
            place=place+2
        end if
    end while
    old_codes=codes[place..length(codes)]
    return pressed_keys
end function
------------------------------------ end keyread.e

new topic     » topic index » view message » categorize

2. Re: Multi-keyread routine

Dear Bolin...

Yes, Your routine must be extremely useful, especially in game program!!!.
I will use your routine in my game program now under development, instead
of using CTRL, ALT, SHIFT key detection routine.

You must post this routine to Euphoria home page, with neat demo program
and detail readme.txt.

a question:

Which value returns, {} or -1, when no key is pressed, in your get_keys()?
I think it's better to return -1 in consistent with other routines of
Euphoria...

Thanks much!

from Lee Woo Seob.

new topic     » goto parent     » topic index » view message » categorize

3. Re: Multi-keyread routine

Thank you also from Augorian!

My games now run faster as they do not have to wait for the get_key()
function to actually return a key press!!

WoHoo!

--Augorian;

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu