If it´s too much trouble to do this, then I might consider dropping keyrepeats for letters. It works for del, backspace and so on which are much more important.
Actually, having just revisted my code, it doesn't do key repeats for alphanumeric keys, either. It's a tricky problem to get around, I guess it just wasn't worth the effort. :)
Anyway, if you still want it, the code's here:
(sorry about the weird tabs - I use 2-space tabs in my IDE)
Graphics 640,480,0,2
SetBuffer BackBuffer()
ClsColor 200,200,200
Const REPEAT_DELAY% = 250
Const REPEAT_RATE% = 25
Const CURSOR_BLINK_RATE% = 500
Const GUI_FONT_NAME$ = "verdana"
Const GUI_FONT_SIZE% = 16
; Key IDs.
Const ID_KEY_NONE% = 0
Const ID_KEY_LEFT% = 1
Const ID_KEY_RIGHT% = 2
Const ID_KEY_HOME% = 3
Const ID_KEY_END% = 4
Const ID_KEY_BACKSPACE% = 5
Const ID_KEY_DELETE% = 6
Const ID_KEY_UP% = 7
Const ID_KEY_DOWN% = 8
Const ID_KEY_PAGE_UP% = 9
Const ID_KEY_PAGE_DOWN% = 10
fps_timer = CreateTimer(60) ; Set to desired FPS.
gui_font = LoadFont(GUI_FONT_NAME$,GUI_FONT_SIZE,True)
SetFont gui_font
; Text input field control vars.
Global i_text$
Global i_selected%
Global i_x%
Global i_y%
Global i_width%
Global i_height%
Global i_first_char%
Global i_cursor_pos%
Global i_cursor_on%
Global i_cursor_timeout%
Global i_title$
Global i_title_x_off%
Global i_old_key%
Global i_key_delay%
Global i_key_timeout%
Global i_backup_width%
Global i_max_chars%
Global i_alt_char$
; Initialize text input field.
i_text$ = "This is the default text"
i_title$ = "Input"
i_title_x_off = StringWidth(i_title$) + 5
i_selected = True
i_width = 280
i_height = GUI_FONT_SIZE
i_x = 100
i_y = 100
i_first_char = 1
i_cursor_pos = Len(i_text$)
i_cursor_on = True
i_cursor_timeout = MilliSecs() + CURSOR_BLINK_RATE
i_old_key = ID_KEY_NONE
i_key_delay = 0
i_key_timeout = 0
i_backup_width = i_width / 4
i_max_chars = 1000
i_alt_char$ = ""
; Main loop.
While Not KeyHit(1)
Cls
check_input_field()
draw_input_field()
WaitTimer(fps_timer)
VWait : Flip False
Wend
End
;
; Ensure first_char is valid in relation to the current cursor position.
;
Function update_input_settings()
text_len = Len(i_text$)
If i_cursor_pos = (i_first_char-1)
; Cursor is at first_char position...
If i_cursor_pos > 0
; Set first_char to be i_backup_width in front of cursor.
i_first_char = i_cursor_pos
width = StringWidth(Mid$(i_text$,i_first_char,1))
While i_first_char > 1
width = width + StringWidth(Mid$(i_text$,i_first_char-1,1))
If width > i_backup_width Then Exit
i_first_char = i_first_char - 1
Wend
EndIf
ElseIf i_cursor_pos < (i_first_char-1)
; Cursor is before first_char...
i_first_char = i_cursor_pos + 1
Else
; Cursor is after first_char...
If i_cursor_pos = text_len
; Cursor is at very end of input text...
; Find character at end of text field.
last_char = i_first_char
width = StringWidth(Mid$(i_text$,last_char,1))
While last_char < text_len
width = width + StringWidth(Mid$(i_text$,last_char+1,1))
If width > i_width Then Exit
last_char = last_char + 1
Wend
If last_char < text_len
; Last char is NOT visible so back up to fill the whole field.
i_first_char = i_cursor_pos
width = StringWidth(Mid$(i_text$,i_first_char,1))
Repeat
width = width + StringWidth(Mid$(i_text$,i_first_char-1,1))
If width > i_width Then Exit
i_first_char = i_first_char - 1
Forever
EndIf
Else
; Cursor is NOT at very end of input text...
char_diff = ((i_cursor_pos + 1) - i_first_char)
If StringWidth(Mid$(i_text$,i_first_char,char_diff+1)) > i_width
; Cursor character won't fit at end of text field...
; First, find the last character we want displayed in the text field.
If i_old_key = ID_KEY_DELETE
last_char = i_cursor_pos + 1
Else
; Set last_char to be i_backup_width in front of cursor.
last_char = i_cursor_pos + 1
width = StringWidth(Mid$(i_text$,last_char,1))
While last_char < text_len
width = width + StringWidth(Mid$(i_text$,last_char+1,1))
If width > i_backup_width Then Exit
last_char = last_char + 1
Wend
EndIf
; Now, back up fron last_char to fill the whole field.
i_first_char = last_char
width = StringWidth(Mid$(i_text$,i_first_char,1))
Repeat
width = width + StringWidth(Mid$(i_text$,i_first_char-1,1))
If width > i_width Then Exit
i_first_char = i_first_char - 1
Forever
EndIf
EndIf
EndIf
End Function
;
;
;
Function draw_input_field()
update_input_settings()
; Draw input field.
Color 0,0,0
Rect i_x-2,i_y-2,i_width+4,i_height+4,True
Text i_x-4-i_title_x_off,i_y,i_title$
; Find cursor bar x coord.
bar_x = i_x
char_diff = ((i_cursor_pos + 1) - i_first_char)
If char_diff > 0
width = StringWidth(Mid$(i_text$,i_first_char,char_diff))
bar_x = bar_x + width
If i_selected
; Draw 'selected text' background.
Color 0,0,255
Rect i_x,i_y,width,i_height,True
EndIf
EndIf
; Draw field text.
Color 255,255,255
x = i_x
width = 0
For n = i_first_char To Len(i_text$)
c$ = Mid$(i_text$,n,1)
c_width = StringWidth(c$)
width = width + c_width
If width > i_width Then Exit
Text x,i_y,c$
x = x + c_width
Next
If i_cursor_on
; Draw cursor bar.
Color 255,255,255
Rect bar_x,i_y,1,i_height,True
EndIf
; Cursor blink management.
If i_cursor_timeout < MilliSecs()
i_cursor_on = Not i_cursor_on
i_cursor_timeout = MilliSecs() + CURSOR_BLINK_RATE
EndIf
End Function
;
;
;
Function check_input_field()
ascii = GetKey()
If KeyDown(56)
; Left Alt key is being held down so check numeric keypad
; for ASCII code being entered.
Select True
Case KeyHit(82)
i_alt_char$ = i_alt_char$ + "0"
Case KeyHit(79)
i_alt_char$ = i_alt_char$ + "1"
Case KeyHit(80)
i_alt_char$ = i_alt_char$ + "2"
Case KeyHit(81)
i_alt_char$ = i_alt_char$ + "3"
Case KeyHit(75)
i_alt_char$ = i_alt_char$ + "4"
Case KeyHit(76)
i_alt_char$ = i_alt_char$ + "5"
Case KeyHit(77)
i_alt_char$ = i_alt_char$ + "6"
Case KeyHit(71)
i_alt_char$ = i_alt_char$ + "7"
Case KeyHit(72)
i_alt_char$ = i_alt_char$ + "8"
Case KeyHit(73)
i_alt_char$ = i_alt_char$ + "9"
End Select
Return
ElseIf i_alt_char$ <> ""
; Left Alt key has just been released with a value contained in
; i_alt_char$ so attempt to convert it into a valid ASCII code.
val = Int(i_alt_char$)
i_alt_char$ = ""
If (val >= 32) And (val <= 255) Then ascii = val
EndIf
If ascii > 31
If i_selected
; Delete initially selected text.
i_text$ = ""
i_cursor_pos = 0
i_first_char = 1
i_selected = False
EndIf
num_chars = Len(i_text$)
If num_chars < i_max_chars
t$ = ""
If i_cursor_pos Then t$ = Mid$(i_text$,1,i_cursor_pos)
t$ = t$ + Chr$(ascii)
If num_chars > i_cursor_pos Then t$ = t$ + Mid$(i_text$,i_cursor_pos+1)
i_text$ = t$
i_cursor_pos = i_cursor_pos + 1
i_cursor_on = True
EndIf
Else
; Give ID to any valid pressed key.
If KeyDown(203)
new_key = ID_KEY_LEFT
ElseIf KeyDown(205)
new_key = ID_KEY_RIGHT
ElseIf KeyDown(199)
new_key = ID_KEY_HOME
ElseIf KeyDown(207)
new_key = ID_KEY_END
ElseIf KeyDown(14)
new_key = ID_KEY_BACKSPACE
ElseIf KeyDown(211)
new_key = ID_KEY_DELETE
Else
new_key = ID_KEY_NONE
EndIf
; Key delay/authorization management.
If (new_key <> ID_KEY_NONE) And (new_key = i_old_key)
If i_key_timeout
If MilliSecs() > i_key_timeout
i_key_timeout = 0
i_key_delay = REPEAT_RATE
EndIf
Else
i_key_timeout = MilliSecs() + i_key_delay
EndIf
Else
i_key_timeout = 0
i_key_delay = REPEAT_DELAY
EndIf
i_old_key = new_key
If (new_key<>ID_KEY_NONE) And (i_key_timeout=0)
; Carry out appropriate key action.
Select new_key
Case ID_KEY_LEFT
If i_cursor_pos > 0
i_cursor_pos = i_cursor_pos - 1
i_cursor_on = True
EndIf
i_selected = False
Case ID_KEY_RIGHT
If i_cursor_pos < Len(i_text$)
i_cursor_pos = i_cursor_pos + 1
i_cursor_on = True
EndIf
i_selected = False
Case ID_KEY_HOME
If i_cursor_pos <> 0
i_cursor_pos = 0
i_cursor_on = True
EndIf
i_selected = False
Case ID_KEY_END
If i_cursor_pos <> Len(i_text$)
i_cursor_pos = Len(i_text$)
i_cursor_on = True
EndIf
i_selected = False
Case ID_KEY_BACKSPACE
If i_selected
; Delete initially selected text.
i_text$ = ""
i_cursor_pos = 0
i_first_char = 1
i_selected = False
ElseIf i_cursor_pos > 0
If i_cursor_pos > 1 Then t$ = Left$(i_text$,i_cursor_pos-1)
If i_cursor_pos < Len(i_text$) Then t$ = t$ + Mid$(i_text$,i_cursor_pos+1)
i_text$ = t$
i_cursor_pos = i_cursor_pos - 1
i_cursor_on = True
EndIf
Case ID_KEY_DELETE
If i_selected
; Delete initially selected text.
i_text$ = ""
i_cursor_pos = 0
i_first_char = 1
i_selected = False
ElseIf i_cursor_pos < Len(i_text$)
If i_cursor_pos > 0 Then t$ = Left$(i_text$,i_cursor_pos)
If i_cursor_pos < (Len(i_text$)-1) Then t$ = t$ + Mid$(i_text$,i_cursor_pos+2)
i_text$ = t$
i_cursor_on = True
EndIf
End Select
EndIf
EndIf
End Function