RSyntaxTextArea icon indicating copy to clipboard operation
RSyntaxTextArea copied to clipboard

RSyntaxTextArea in JInternalFrame: Can't type a single character

Open stefan-reich opened this issue 6 years ago • 24 comments

OK, this is high priority for me... I have a simple RSyntaxTextArea in an RTextScrollPane in a JInternalFrame in a JDesktopPane where I can't type anything.

Adding a KeyListener directly to the text area shows that it receives normal key events.

Bug is reproducible every time.

What can I add to the code to investigate?

stefan-reich avatar Jun 06 '18 15:06 stefan-reich

I think I have a hint... RSyntaxTextArea might not be compatible with its library being loaded multiple times (I use classloaders extensively).

More precisely, in the AppContext's table there is an entry:

JTextComponent_KeymapTable = {BasicTextAreaUI=Keymap[BasicTextAreaUI]{}, MetalTextFieldUI=Keymap[MetalTextFieldUI]{}, default=Keymap[default]{}, RTextAreaKeymap=Keymap[RTextAreaKeymap]{}, SubstanceTextFieldUI=Keymap[SubstanceTextFieldUI]{}, SubstanceTextAreaUI=Keymap[SubstanceTextAreaUI]{}}

...which, I strongly assume, fails when there is more than one instance of the RSyntaxTextArea library.

stefan-reich avatar Jun 10 '18 14:06 stefan-reich

FIXED FIXED FIXED FIXED FIXED!

Proof for 2 working RSyntaxTextAreas w/different class loaders.

RSyntaxTextArea indeed does not like to be loaded more than once due to the AppContext problem outlined above. I now load the library only once which is acceptable for the start.

@bobbylight: If you want to improve this, please provide a function that unregisters all keymaps from Swing's UI defaults.

Then it will be possible to unload the library if it's not needed anymore. I have a long-running OS which is a single Java VM and loads and unloads modules all the time. Only some of those modules use RSyntaxTextArea, so it is a waste of memory to keep the library around when no longer needed.

stefan-reich avatar Jun 10 '18 20:06 stefan-reich

I found the very same problem while writing a plugin for Burp proxy. If you use another plugin that uses RSyntaxTextArea, then your plugin cannot use it because of this problem (or at least cant use for editing).

Is there any workaround when we have no control over the library loading?

pwntester avatar Mar 21 '19 12:03 pwntester

I'm not too sure what the issue is here, it's been awhile since I've had to worry about multiple classloaders in an app before. Can either of you provide more specific guidance on what a remedy would entail?

Sent from my Nexus 6p

On Thu, Mar 21, 2019, 8:58 AM Alvaro [email protected] wrote:

I found the very same problem while writing a plugin for Burp proxy. If you use another plugin that uses RSyntaxTextArea, then your plugin cannot use it because of this problem (or at least cant use for editing).

Is there any workaround when we have no control over the library loading?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bobbylight/RSyntaxTextArea/issues/269#issuecomment-475218527, or mute the thread https://github.com/notifications/unsubscribe-auth/ABjmFrrOwhlIeQE66Co196lMqVVtMrl8ks5vY4IBgaJpZM4Uc2lC .

bobbylight avatar Mar 21 '19 14:03 bobbylight

I have no idea to be honest since the classloading is not under my control in this case. Maybe @stefan-reich can provide some insights

pwntester avatar Mar 21 '19 20:03 pwntester

Hi @pwntester

I have the exact same issue for the SAML Raider Burp extension. It's not usable right now because of this. :(

Does anyone knows a workaround?

emanuelduss avatar Apr 01 '19 13:04 emanuelduss

provide a function that unregisters all keymaps from Swing's UI defaults.

These global keymaps are the problem. They always point to only one of the library instances, making the other ones unusable. If @bobbylight can make the library work without registering anything in Swing's UI defaults, we're good to go.

stefan-reich avatar Apr 01 '19 13:04 stefan-reich

There is a version that would resolve this bug: https://github.com/federicodotta/RSyntaxTextArea/commit/f20fc88fe47e320e32f5fea3b09518a67e26974d

@bobbylight Is it possible that this will be merged into your version?

emanuelduss avatar Apr 01 '19 13:04 emanuelduss

It's not a perfect fix (doesn't allow multiple library instances to work concurrently), but it might work for your specific problem. And it's not worse than what's currently in the library, so yeah, I say merge it.

stefan-reich avatar Apr 01 '19 13:04 stefan-reich

I can take a look, but I'm not sure I fully understand what's going on here. If it's really a matter of some other ClassLoader's RSTA keymap table in the Swing AppContext, wouldn't this same problem happen for all Swing JTextComponents (since AFAIK RSTA does the same thing as other Swing components)?

bobbylight avatar Aug 05 '19 21:08 bobbylight

It might not be the perfect fix, but works great in my case too, thx @mindfuckup !

cmoine avatar Aug 13 '19 14:08 cmoine

what a bummer this problem still exists

ozzi- avatar Feb 07 '20 17:02 ozzi-

Hi @bobbylight,

my name is Federico and I'm another developer who would like to use your great library to develop a plugin for Burp Suite (a tool used by security researcher and penetration tester). I developed a fix that worked on the previous version of Burp Suite (the one posted by @mindfuckup). New version of Burp Suite seems to use your library on his core and when my plugin is loaded there are issues in the tool. In detail the instance of RSyntaxTextArea used by the core of the tool stop working, due to the bug highlighted by @stefan-reich. In fact two instances of your plugin are loaded in two different ClassLoaders and when the second instance is loaded the first stop working (probably for the global keymaps).

I paste a small example that you can compile and run to replicate the issue. It load two frames and typing works only in the second one while in the first is stucked (when you run this example RSyntaxTextArea library should NOT be in Java classpath):

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.Component;
import java.io.File;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;

public class Test {

	public static void main(String[] args) {

		try {
	    	 
			// First RSyntaxTextArea instance
			JFrame frame1 = new JFrame("Frame1");
			frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);			   
			JPanel cp1 = new JPanel(new BorderLayout());			   		
			File file = new File("FULL_PATH_TO_JAR\\rsyntaxtextarea-3.1.0.jar");
			URL url = file.toURI().toURL();
			  
			URLClassLoader classLoader1 = new URLClassLoader(new URL[] {url});
			Class classToLoad = classLoader1.loadClass("org.fife.ui.rsyntaxtextarea.RSyntaxTextArea");			
			Class[] argTypes = {int.class,int.class};
			Constructor constructor = classToLoad.getDeclaredConstructor(argTypes);
			Object[] arguments = {new Integer(20),new Integer(60)};
			Component textArea1 = (Component)constructor.newInstance(arguments);
			  
			cp1.add(textArea1);
			  
			frame1.getContentPane().add(cp1, BorderLayout.CENTER);
			frame1.pack();
			frame1.setVisible(true);			  
			  
			// Second RSyntaxTextArea instance (with a DIFFERENT class loader)			
			JFrame frame2 = new JFrame("FrameDemo3");
			frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);			   
			JPanel cp2 = new JPanel(new BorderLayout());			   		
			File file2 = new File("FULL_PATH_TO_JAR\\rsyntaxtextarea-3.1.0.jar");
			URL url2 = file2.toURI().toURL();
			  
			URLClassLoader classLoader2 = new URLClassLoader(new URL[] {url2});
			Class classToLoad2 = classLoader2.loadClass("org.fife.ui.rsyntaxtextarea.RSyntaxTextArea");			
			Class[] argTypes2 = {int.class,int.class};
			Constructor constructor2 = classToLoad2.getDeclaredConstructor(argTypes2);
			Object[] arguments2 = {new Integer(20),new Integer(60)};
			Component textArea2 = (Component)constructor2.newInstance(arguments2);			  
			cp2.add(textArea2);
			  
			frame2.getContentPane().add(cp2, BorderLayout.CENTER);
			frame2.pack();
			frame2.setVisible(true);
			
			// Check if the classloaders are different
			System.out.println(classToLoad2 == classToLoad);
			
      }catch(Exception e) {
    	  e.printStackTrace();
      }
   }

}

Thank you for your great work!

Federico

federicodotta avatar Mar 11 '20 19:03 federicodotta

@pwntester @mindfuckup Do you succeeded in making your plugins work in Burp Suite 2 with the new Repeater? Thank you.

federicodotta avatar Mar 12 '20 08:03 federicodotta

Ni @federicodotta

No, I completely removed RSyntaxTextArea from my Burp Plugin (SAML Raider) because it was not usable anymore (input did not work anymore). I can live without syntax highlighting.

Regards, Emanuel

emanuelduss avatar Mar 12 '20 08:03 emanuelduss

@mindfuckup @pwntester Good news! https://forum.portswigger.net/thread/burp-suite-2-and-rsyntaxtextarea-library-5316570c

federicodotta avatar Mar 12 '20 11:03 federicodotta

Does that mean, new releases will fix the conflict?

ozzi- avatar Mar 16 '20 15:03 ozzi-

Hi, I just tried with the version 2020.2.1 of Burp Suite, released today. Now it works correctly using my modified version of RSyntaxText area, also loading multiple extensions that use RSyntaxTextArea. Unfortunately original RSyntaxtTextArea still does not work.

federicodotta avatar Mar 17 '20 15:03 federicodotta

with burp 2020v4 it seems to work with default rsyntaxtextarea!

Check the latest answer of portswigger https://forum.portswigger.net/thread/burp-suite-2-and-rsyntaxtextarea-library-5316570c

ozzi- avatar Apr 27 '20 14:04 ozzi-

It can also be done by removing the Keymap before initializing RSyntaxTextArea

(javax.swing.text.JTextComponent/removeKeymap "RTextAreaKeymap")
;; Then, this will work
(org.fife.ui.rsyntaxtextarea.RSyntaxTextArea.)

I test burp Repeater, It also do this when create new instance tab.

Thanks for your patch info.

There is a version that would resolve this bug: federicodotta@f20fc88

@bobbylight Is it possible that this will be merged into your version?

ntestoc3 avatar May 11 '20 09:05 ntestoc3

Also need to clear the action and input map, otherwise backspace and carriage return will not work.

Burp Repeater didn't do it, so new created Repeater can't do backspace and carriage return action, you need to restore the original value after creating RSyntaxTextArea.

  (javax.swing.UIManager/put "RSyntaxTextAreaUI.actionMap" nil)
  (javax.swing.UIManager/put "RSyntaxTextAreaUI.inputMap" nil)
  (javax.swing.UIManager/put "RTextAreaUI.actionMap" nil)
  (javax.swing.UIManager/put "RTextAreaUI.inputMap" nil)

It can also be done by removing the Keymap before initializing RSyntaxTextArea

(javax.swing.text.JTextComponent/removeKeymap "RTextAreaKeymap")
;; Then, this will work
(org.fife.ui.rsyntaxtextarea.RSyntaxTextArea.)

I test burp Repeater, It also do this when create new instance tab.

Thanks for your patch info.

There is a version that would resolve this bug: federicodotta@f20fc88 @bobbylight Is it possible that this will be merged into your version?

ntestoc3 avatar May 11 '20 10:05 ntestoc3

Also need to clear the action and input map, otherwise backspace and carriage return will not work.

Burp Repeater didn't do it, so new created Repeater can't do backspace and carriage return action, you need to restore the original value after creating RSyntaxTextArea.

  (javax.swing.UIManager/put "RSyntaxTextAreaUI.actionMap" nil)
  (javax.swing.UIManager/put "RSyntaxTextAreaUI.inputMap" nil)
  (javax.swing.UIManager/put "RTextAreaUI.actionMap" nil)
  (javax.swing.UIManager/put "RTextAreaUI.inputMap" nil)

It can also be done by removing the Keymap before initializing RSyntaxTextArea

(javax.swing.text.JTextComponent/removeKeymap "RTextAreaKeymap")
;; Then, this will work
(org.fife.ui.rsyntaxtextarea.RSyntaxTextArea.)

I test burp Repeater, It also do this when create new instance tab. Thanks for your patch info.

There is a version that would resolve this bug: federicodotta@f20fc88 @bobbylight Is it possible that this will be merged into your version?

I can use it with initial like this:

JTextComponent.removeKeymap("RTextAreaKeymap");
textArea = new RSyntaxTextArea();
UIManager.put("RSyntaxTextAreaUI.actionMap", null);
UIManager.put("RSyntaxTextAreaUI.inputMap", null);
UIManager.put("RTextAreaUI.actionMap", null);
UIManager.put("RTextAreaUI.inputMap", null);

lijicheng168 avatar Feb 10 '21 00:02 lijicheng168

Wait, so the following is enough to make it run with Burp? With which version of RSyntax?

JTextComponent.removeKeymap("RTextAreaKeymap");
textArea = new RSyntaxTextArea();
UIManager.put("RSyntaxTextAreaUI.actionMap", null);
UIManager.put("RSyntaxTextAreaUI.inputMap", null);
UIManager.put("RTextAreaUI.actionMap", null);
UIManager.put("RTextAreaUI.inputMap", null);

Cheers

  • Edit : this actually works very well with default rysntax text area and the latest burp

ozzi- avatar Feb 11 '21 17:02 ozzi-

I am having the same issue. I do not use Burp Suit, but we have another modules based project running code via different class loaders. The above fix examples helped me, but I still would like to have it fixed in the library.

Thanks

nyckyta avatar Sep 06 '22 13:09 nyckyta