B4J Question unable to stuff clipboard

drgottjr

Expert
Licensed User
Longtime User
problem: edit something captured from clipboard before user pastes it into app.

if you copy multiline text for pasting into a single line textfield, the CRLF or CR or LF chars are essentially ignored when the user pastes the text. in theory, this is ok, except the last word on one
line is joined together with the first word on the next line, creating a single, potentially nonsensical word. (the app parses what it sees in the textfield). if i could replace instances of CRLF or CR or LF with a space - thus separating 2 words - that would be ideal for my purposes. (yes, i could use a multiline textfield, but that introduces a different set of issues.)

i'm using the jNativeHookB4j library, jNativeHook.jar and the KeyComboListener class for the application.

so, intercepting ctrl + "v" (paste) doesn't work as expected since it's triggered after the combination is pressed. (i was looking for it to kick in before the os sees it. after is too late.) so i switched tactics
and captured when the user has pressed ctrl + "c" (copy). i thought i would scan the captured clipboard text to see if there were any instances of CRLF, CR or LF, and - if so - replace them with a space.
i would then returned the new text to the clipboard (fx.setString()). when the user pressed ctrl + "v" to paste, i would simply let nature takes its course.

while i am able to capture the text in the clipboard and, apparently, put a modified version back (no error triggered), the text which was originally in the clipboard still appears in the textfield when the user pastes.

here is the code:
(as mentioned, capturing the key presses and fx.Clipboard.GetString work as expected)
<code>
Sub kcl_KeyComboPressed ' ie, ctrl + "c"
' Log(kcl.GetKeyComboStringRepresentation & " pressed.")
If fx.Clipboard.HasString Then
Dim gotString As String = fx.Clipboard.GetString
' Log("got:" & gotString)
gotString = "my new text would go here" ' RegexReplaceAll("[\r\n]", gotString, "")
fx.Clipboard.SetString( gotString )
Else
Log("nothing for you at this time")
End If
End Sub
</code>

what am i missing?
 

stevel05

Expert
Licensed User
Longtime User
It's difficult without being able to test it, but I would try creating a new sub to fill the clipboard and calling it with CallSubDelayed, so it is not being processed within the KeyPressed Event sub.

BTW, code blocks on the forum use square brackets.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
It's difficult without being able to test it, but I would try creating a new sub to fill the clipboard and calling it with CallSubDelayed, so it is not being processed within the KeyPressed Event sub.

BTW, code blocks on the forum use square brackets.

yeah, callsubdelayed does allow me to assign a string value to the clipboard. thanks.
-go
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
The KeyComboListener event subs run in the main thread. This means you can't consume the KeyPressed events from those subs. Conversely, the raw NativeHook event subs run in the NativeHook delegate thread which allows you to consume events. If you watch for "ctrl_v" or "ctrl_c" using the old method (creating global Booleans for ControlDown, etc...) you can consume those events before they propagate to the rest of the system.
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
The KeyComboListener event subs run in the main thread. This means you can't consume the KeyPressed events from those subs. Conversely, the raw NativeHook event subs run in the NativeHook delegate thread which allows you to consume events. If you watch for "ctrl_v" or "ctrl_c" using the old method (creating global Booleans for ControlDown, etc...) you can consume those events before they propagate to the rest of the system.

yeah, it started to become clear that i would have to resort to doing what keycombolistener was designed to avoid. capturing ctrl + c before the user hits ctrl + v is a workaround that sort of works. after capturing ctrol + c, i call callsubdelayed to do what i wanted with the contents of the clipboard. then, when the user hits ctrl + v, he sees what i put in the clipboard. there are, however, still some issues, so i'll be looking at the old nativehook method.

thanks for the input.
 
Upvote 0

Roycefer

Well-Known Member
Licensed User
Longtime User
Another option is to modify the code of KeyComboListener. It's just a simple B4J class so you can go in and modify it to suit your needs. All the code in kcl.KeyPressed() runs in the NativeHook delegate thread (provided kcl.KeyPressed() is called inside nh_NativeKeyPressed). You modify kcl.KeyPressed() to have a Boolean return value and use that to decide whether or not to consume the native key event.
B4X:
Sub nh_NativeKeyPressed(nke As NativeKeyEvent) As Boolean
   Dim consume as Boolean = kcl.KeyPressed(nke)   'this is the modified version of kcl.KeyPressed()
   'blah blah blah, do some other stuff.....
   Return consume   'if consume==True, then this native key event should be prevented from propagating through the system.
End Sub
modified kcl sub:
B4X:
'Call this inside your NativeHook_KeyPressed event sub
Public Sub KeyPressed(nke As NativeKeyEvent) As Boolean
    If Not(Listening) Then Return
    For j = 0 To KeyList.Size-1
        Dim k As String = KeyList.Get(j)
        Dim kt As String = nke.KeyText.ToLowerCase
        If kt.Contains(" ") And kt.Contains(k) And k.Length>1 Then
            KeysDown(j)=True
        Else if kt==k Then
            KeysDown(j)=True
        End If
    Next
    If BooleanArrayStatus(KeysDown) Then
        RaiseEvent
        Return True
    End If
    Return False
End Sub
 
Upvote 0

drgottjr

Expert
Licensed User
Longtime User
Another option is to modify the code of KeyComboListener. It's just a simple B4J class so you can go in and modify it to suit your needs. All the code in kcl.KeyPressed() runs in the NativeHook delegate thread (provided kcl.KeyPressed() is called inside nh_NativeKeyPressed). You modify kcl.KeyPressed() to have a Boolean return value and use that to decide whether or not to consume the native key event.
B4X:
Sub nh_NativeKeyPressed(nke As NativeKeyEvent) As Boolean
   Dim consume as Boolean = kcl.KeyPressed(nke)   'this is the modified version of kcl.KeyPressed()
   'blah blah blah, do some other stuff.....
   Return consume   'if consume==True, then this native key event should be prevented from propagating through the system.
End Sub
modified kcl sub:
B4X:
'Call this inside your NativeHook_KeyPressed event sub
Public Sub KeyPressed(nke As NativeKeyEvent) As Boolean
    If Not(Listening) Then Return
    For j = 0 To KeyList.Size-1
        Dim k As String = KeyList.Get(j)
        Dim kt As String = nke.KeyText.ToLowerCase
        If kt.Contains(" ") And kt.Contains(k) And k.Length>1 Then
            KeysDown(j)=True
        Else if kt==k Then
            KeysDown(j)=True
        End If
    Next
    If BooleanArrayStatus(KeysDown) Then
        RaiseEvent
        Return True
    End If
    Return False
End Sub

always good to have a plan b. thanks. kcl was presented as a convenient way to use the nativehook library. since i wasn't familiar with that library and, frankly, since this particular operation was not crucial to the application, i went with convenience. now my curiosity has been piqued, so i'm going to look at nativehook without kcl and with your modified kcl. thanks again.
 
Upvote 0
Top