Code:
Imports System.Threading
Imports System
Imports System.ComponentModel

Imports System.Windows.Forms

Public Form1 w/e
Dim Loope As Boolean
    Private demoThread As Thread = Nothing
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
    Public Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Delegate Sub SetTextCallback(ByVal [text] As String)

Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        While Loope = False
            If GetAsyncKeyState(&H10) Then
                Me.demoThread = New Thread( _
                New ThreadStart(AddressOf Me.ThreadProcSafe))

                Me.demoThread.Start()

                Loope = True
            End If
            Sleep(100)
        End While
    End Sub

  Private Sub ThreadProcSafe()
        Me.SetText("sh")
    End Sub

    Private Sub SetText(ByVal [text] As String)

        ' InvokeRequired required compares the thread ID of the
        ' calling thread to the thread ID of the creating thread.
        ' If these threads are different, it returns true.
        If Me.Label1.InvokeRequired Then

            Dim d As New SetTextCallback(AddressOf SetText)
            Me.Invoke(d, New Object() {[text]})
        Else
            Me.Label1.Text += [text] + " "
        End If
    End Sub
I'm not sure if I'm doing this right but I think I'm doing a crossover of threads correctly. If there's an easier way, please help me.

Also when i record keystrokes, i want it to record by key down. I'm not really sure what I should use. What I used is use GetASyncState to record the shift key. It writes "(sh)" in a label. If I hold the Shift button, it keeps recording it. How would I make it so then it doesn't record like 1zillion?