blob: f326e6a833437f6d1ead317c79bc546f9ffb4f9c [file] [log] [blame]
purpose: Interactive keyboard test shows which keys are pressed
\ See license at end of file
: bounded? ( n lower size -- flag ) bounds swap within ;
: inside? ( tx ty x y w h -- flag )
>r ( tx ty x y w r: h )
swap >r ( tx ty x w r: h y )
rot >r ( tx x w r: h y ty )
bounded? if ( r: h y ty )
r> r> r> bounded? ( flag )
else ( r: h y ty )
r> r> r> 3drop ( )
false ( flag )
then ( flag )
;
dev /touchscreen
new-device
" hotspot" device-name
: open ( -- okay? ) true ;
: close ;
0 0 instance 2value hit-xy
0 0 instance 2value hit-wh
0 0 instance 2value the$
0 0 instance 2value returning$
: set-hotspot ( x y w h $ -- ) ?save-string to the$ to hit-wh to hit-xy ;
: hit? ( -- flag )
" pad?" $call-parent 0= if ( )
false exit ( -- false )
then ( pad-x,y,z down? contact# )
drop if ( pad-x,y,z )
drop hit-xy hit-wh inside? ( flag )
else ( pad-x,y,z )
3drop false ( false )
then ( flag )
;
: read ( adr len -- actual | -1 )
0= if drop -1 exit then ( adr )
returning$ dup if ( adr adr1 len1 )
over c@ -rot ( adr char adr1 len1 )
1 /string to returning$ ( adr char )
swap c! 1 exit ( -- actual )
else ( adr adr1 len1 )
2drop ( adr )
then ( adr )
hit? if ( adr )
the$ to returning$ ( )
then ( adr )
returning$ dup if ( adr adr1 len1 )
over c@ -rot ( adr char adr1 len1 )
1 /string to returning$ ( adr char )
swap c! 1 exit ( -- actual )
else ( adr adr1 len1 )
2drop ( adr )
then ( adr )
drop -1
;
finish-device
device-end
dev /touchscreen
new-device
" keyboard" device-name
hex
struct
/w field >key-x
/w field >key-y
/w field >key-w
/w field >key-h
/c field >key-code1
/c field >key-code2
constant /key
/key d# 128 * buffer: keys
0 value #keys
0 value key-y
0 value key-x
d# 8 constant key-gap
d# 10 constant row-gap
d# 0 constant hidden-key-w
d# 60 constant smulti-key-w
d# 60 constant single-key-w
d# 60 constant single-key-h
d# 90 constant shift-key-w
d# 460 constant space-key-w
d# 400 constant top-row-offset
d# 34 constant button-w
d# 34 constant button-h
: key-adr ( i -- adr ) /key * keys + ;
0 value codes1
0 value codes2
: set-codes ( adr2 len2 adr1 len1 -- ) drop to codes1 drop to codes2 ;
: set-key-code ( key -- )
key-adr ( 'key )
codes1 c@ over >key-code1 c! 1 codes1 + to codes1
codes2 c@ swap >key-code2 c! 1 codes2 + to codes2
;
: top-key-row ( -- ) top-row-offset to key-y key-gap to key-x ;
: next-key-row ( -- )
key-y single-key-h + row-gap + to key-y
key-gap to key-x
;
: #keys++ ( -- ) #keys 1+ to #keys ;
: ++key-x ( n -- ) key-x + to key-x ;
: add-key-gap ( -- ) key-gap ++key-x ;
: (make-key) ( x y w h -- )
#keys key-adr >r
r@ >key-h w! r@ >key-w w! r@ >key-y w! r@ >key-x w!
r> drop
#keys set-key-code
#keys++
;
: make-key ( w -- ) dup key-x key-y rot single-key-h (make-key) ++key-x ;
: make-key&gap ( w -- ) make-key add-key-gap ;
: make-single-key ( -- ) single-key-w make-key&gap ;
: blank-single-key ( -- ) single-key-w ++key-x add-key-gap ;
: make-smulti-key ( i -- )
1 and if
hidden-key-w make-key
else
smulti-key-w make-key
then
;
: make-double-key ( -- ) single-key-w 2* make-key&gap ;
: make-shift-key ( -- ) shift-key-w make-key&gap ;
: make-space-key ( -- ) space-key-w make-key&gap ;
: make-quad-key ( -- )
key-x key-y single-key-w 2* dup >r single-key-h 2* row-gap + (make-key)
r> ++key-x
add-key-gap
;
0 [if]
: make-button ( x y -- ) button-w button-h (make-key) ;
: make-buttons
d# 68 d# 25 make-button \ Rocker up 65
d# 25 d# 68 make-button \ Rocker left 67
d# 110 d# 68 make-button \ Rocker right 68
d# 68 d# 110 make-button \ Rocker down 66
d# 68 d# 196 make-button \ Rotate 69
d# 918 d# 25 make-button \ O e0 65
d# 875 d# 68 make-button \ square e0 67
d# 960 d# 68 make-button \ check e0 68
d# 918 d# 110 make-button \ X e0 66
;
[then]
: make-keys ( -- )
0 to #keys
top-key-row
" ~!@#$%^&*()_+"b"
" '1234567890-="b" set-codes
d# 13 0 do make-single-key loop
make-double-key
next-key-row
" "tQWERTYUIOP{}"r"
" "tqwertyuiop[]"r" set-codes
d# 13 0 do make-single-key loop
make-quad-key
next-key-row
" "(80)ASDFGHJKL:""|"
" "(80)asdfghjkl;'\" set-codes
d# 13 0 do make-single-key loop
next-key-row
" "(81)ZXCVBNM<>?"(8186)" \ 86 may be unused
" "(81)zxcvbnm,./"(8182)" set-codes \ 82 may be unused
make-shift-key
d# 10 0 do make-single-key loop
make-shift-key
make-single-key
next-key-row
" "(1b) "(878889)"
" "(1b) "(838485)" set-codes
make-single-key
2 0 do blank-single-key loop
make-space-key
2 0 do blank-single-key loop
3 0 do make-single-key loop
\ make-buttons
;
: >key-bounds ( 'key -- x y w h )
>r r@ >key-x w@ r@ >key-y w@ r@ >key-w w@ r> >key-h w@
;
: key-hit? ( x y key# -- )
key-adr >key-bounds inside?
;
: find-key? ( x y -- false | key# true )
#keys 0 do ( x y )
2dup i key-hit? if ( x y )
2drop i true ( key# true )
unloop exit ( -- key# true )
then ( x y )
loop ( x y )
2drop false ( false )
;
\ 80 ctrl 81 shift
\ 82 up 83 left 84 down 85 right
\ 86 pg up 87 home 88 pg dn 89 end
h# f81f constant down-key-color
h# 07ff constant tested-key-color
h# 001f constant idle-key-color
h# ffff constant kbd-bc
0 value esc?
: key-inset ( dx dy 'key -- x y )
>key-bounds 2drop ( dx dy x y )
rot + >r + r> ( x y )
;
: string-label ( adr len 'key -- )
d# 15 d# 25 rot key-inset ( adr len x y )
type-at-xy ( )
;
: special-label? ( char -- flag ) h# 20 h# 7e between 0= ;
: special-label ( char 'key -- )
>r ( char r: 'key )
case
h# 08 of " Backspace" r> string-label endof
h# 09 of " Tab" r> string-label endof
h# 1b of " Esc" r> string-label endof
h# 80 of " Ctrl" r> string-label endof
h# 81 of " Shift" r> string-label endof
h# 86 of " Up" r> string-label endof
h# 87 of " Left" r> string-label endof
h# 88 of " Down" r> string-label endof
h# 89 of " Right" r> string-label endof
h# 0d of " Enter" d# 35 d# 55 r> key-inset type-at-xy endof
( default ) r> drop
endcase
;
: label-key ( color 'key -- )
>r to char-bg kbd-bc to char-fg ( r: 'key )
r@ >key-code2 c@ ( char r: 'key )
dup special-label? if ( char r: 'key )
r> special-label exit ( )
then ( char r: 'key )
dup [char] A [char] Z between if ( letter r: 'key )
d# 10 d# 10 r> key-inset ( char x y )
character-at-xy ( )
else ( char r: 'key )
d# 40 d# 10 r@ key-inset ( char x y r: 'key )
character-at-xy ( r: 'key )
r@ >key-code1 c@ ( char x y r: 'key )
d# 25 d# 35 r> key-inset ( char x y )
character-at-xy ( )
then
;
: draw-key ( key# color -- )
swap key-adr >r ( color r: 'key )
r@ >key-w w@ hidden-key-w = if ( color r: 'key )
r> 2drop ( )
else ( color r: 'key )
dup r@ >key-bounds ( color x y w h r: 'key )
" fill-rectangle" $call-screen ( color r: 'key )
r> label-key ( )
then
;
0 0 instance 2value returning$
1 instance buffer: the-char
: return-string ( adr len -- ) to returning$ ;
: return-char ( ascii -- )
the-char c! the-char 1 return-string
;
0 value ctrl?
0 value shift?
: return-key# ( key# -- )
key-adr ( 'key )
shift? if >key-code2 else >key-code1 then c@ ( code )
dup h# 80 >= if ( code )
case
h# 80 of true to ctrl? endof
h# 81 of true to shift? endof
h# 82 of " "(1b)[A" return-string endof \ Up
h# 83 of " "(1b)[D" return-string endof \ Left
h# 84 of " "(1b)[B" return-string endof \ Down
h# 85 of " "(1b)[C" return-string endof \ Right
h# 86 of " "(1b)[5~" return-string endof \ PgUp
h# 87 of " "(1b)[1~" return-string endof \ Home
h# 88 of " "(1b)[6~" return-string endof \ PgDn
h# 89 of " "(1b)[4~" return-string endof \ End
\ Rest are reserved
endcase
exit ( -- )
then ( code )
ctrl? if ( code )
dup h# 40 h# 7f between if ( code )
h# 1f and return-char ( )
else ( code )
drop ( )
then ( )
exit
then ( code )
return-char ( )
;
: cancel-shifts ( key# -- )
key-adr >key-code1 c@ ( code )
case
h# 80 of false to ctrl? endof
h# 81 of false to shift? endof
\ Rest are reserved
endcase
;
: key-down ( key# -- ) down-key-color draw-key ;
: key-up ( key# -- )
dup cancel-shifts
idle-key-color draw-key
;
: fill-screen ( color -- )
0 0 " dimensions" $call-screen " fill-rectangle" $call-screen
;
struct
/n field >contact-time
/n field >contact-key#
constant /contact
d# 10 /contact * buffer: contacts
: >contact ( contact# -- 'contact ) /contact * contacts + ;
: cancel-contact ( contact# -- ) >contact >contact-key# off ;
: get-contact-key#? ( contact# -- false | key# true )
>contact >contact-key# @ ( n )
dup if 1- true then ( false | key# true )
;
: set-contact-key# ( contact# key# -- )
1+ swap ( key#' contact# )
>contact >contact-key# ! ( )
;
d# 100 value short \ Auto-repeat interval in ms
d# 1000 value long \ Initial auto-repeat interval in ms
: set-repeat ( contact# interval -- )
get-msecs + ( adr ascii contact# new-time )
swap >contact >contact-time ! ( adr ascii contact# new-time )
;
: get-repeat ( contact# -- time ) >contact >contact-time @ ;
\ Records the contact and returns the key code if there is one
: return-key-code ( contact# key# -- )
over long set-repeat ( contact# key# ) \ Set repeat time
tuck set-contact-key# ( key# ) \ Remember key
return-key# ( )
;
\ Called when a finger is still down in the same key area as before.
\ Repeats the key code when the time is right.
: ?repeated ( contact# key# -- )
swap dup get-repeat ( key# contact# time )
get-msecs - 0<= if ( key# contact# )
short set-repeat ( key# )
return-key# ( )
else ( key# contact# )
2drop ( )
then ( )
;
: press-key ( x y contact# -- )
-rot find-key? if ( contact# key# )
\ The event happened in a key area
over get-contact-key#? if ( contact# key# old-key# )
\ Continued press
2dup = if ( contact# key# old-key# )
\ Same - check for auto-repeat
drop ( contact# key# )
?repeated ( )
else ( contact# key# old-key# )
\ Different - release old key and activate new one
key-up ( contact# key# )
dup key-down ( contact# key# )
return-key-code ( )
then ( )
else ( contact# key# )
\ New keypress
dup key-down ( contact# key# )
return-key-code ( )
then
else ( contact# )
\ The event happened outside a key area
dup get-contact-key#? if ( contact# old-key# )
\ Moved out of key area - release key
key-up ( contact# )
cancel-contact ( )
else ( contact# )
\ Press in blank area with nothing down
drop ( )
then ( )
then ( )
;
: release-key ( x y contact# -- )
dup get-contact-key#? if ( x y contact# key# )
key-up ( x y contact# )
then ( x y contact# )
cancel-contact ( x y )
2drop ( )
;
: read ( adr len -- actual | -1)
0= if drop -1 exit then ( adr )
returning$ dup if ( adr adr1 len1 )
over c@ -rot ( adr char adr1 len1 )
1 /string to returning$ ( adr char )
swap c! 1 exit ( -- actual )
else ( adr adr1 len1 )
2drop ( adr )
then ( adr )
" pad?" $call-parent 0= if ( adr )
drop -1 exit ( -- -1 )
then ( adr x y z down? contact# )
rot drop swap if ( adr x y contact# )
press-key ( adr )
else ( adr x y contact# )
release-key ( adr )
then ( adr )
returning$ dup if ( adr adr1 len1 )
over c@ -rot ( adr char adr1 len1 )
1 /string to returning$ ( adr char )
swap c! 1 exit ( -- actual )
else ( adr adr1 len1 )
2drop ( adr )
then ( adr )
drop -1
;
0 [if]
: poller ( -- )
begin here 1 read 0> if here c@ emit then ukey? until
;
[then]
: erase-keyboard ( color -- )
kbd-bc 0 top-row-offset ( color x y )
" dimensions" $call-screen 2over xy- ( color x y w h )
" fill-rectangle" $call-screen ( )
;
: draw-keyboard ( -- )
kbd-bc fill-screen
#keys 0 ?do i key-up loop
;
variable buf
: flush ( -- )
begin buf 1 read 0< until
;
: open ( -- okay? )
make-keys
draw-keyboard
" flush" $call-parent
true
;
: close ( -- )
flush
erase-keyboard
;
finish-device
device-end
\ LICENSE_BEGIN
\ Copyright (c) 2007 FirmWorks
\
\ Permission is hereby granted, free of charge, to any person obtaining
\ a copy of this software and associated documentation files (the
\ "Software"), to deal in the Software without restriction, including
\ without limitation the rights to use, copy, modify, merge, publish,
\ distribute, sublicense, and/or sell copies of the Software, and to
\ permit persons to whom the Software is furnished to do so, subject to
\ the following conditions:
\
\ The above copyright notice and this permission notice shall be
\ included in all copies or substantial portions of the Software.
\
\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\
\ LICENSE_END