how to set text in a text area and keep the undo working?

I have been fighting with this on and off for years and I guess I’ve decided to fight with it again. I need to be able to make changes to the text in a textarea and allow that to be undone as if it had been done by the user. Right now if you change the .text property that resets the undo queue. There seems no programmatic way that I can find to change text in a textArea that doesn’t delete the undo queue. Setting the selText is also not undoable through the built in system support.

I have the MBS plugins and have experimented with changing the underlying NSTextContainers or NSTextStorage objects but I either get the same behavior or I get crashes of the app as it tries to do something not knowing that the text has changed.

I have been using a custom undo editfield that saves off the contents of the field into a queue whenever an undoable action happens, but it’s a little wonky and doesn’t support styled text as well as I would like. I don’t want to waste any more time with that since the system should be able to handle this for me if I only knew how to tell it to save an undo point here and don’t reset your undo queue whenever I make a programmatic change to the field.

There must be a way to do this using the underlying cocoa controls references that I can get access to through the MBS plugins, but I am unable to figure it out. I’ve been reading Apple’s docs on and off as well but I don’t see a direct reference to this sort of thing anywhere. My searching has not been throughout though so if anyone can point me to a place to start to figure it out that would be greatly appreciated.

the NSUndoManager seems the obvious place to start, but at least in the MBS plugin it seems mostly for implementing your own undo for non-text field type interfaces which would be useful to understand for other things but doesn’t really help me here. The text fields are already registered with the undomanager of the window they are in. Every time I’ve tried to experiment with calling it’s start and stop coalescing methods directly I get crashes as things get out of sync with the built in xojo controls.

Thanks!

you can look into this old project

https://forum.xojo.com/conversation/post/331297

thats a very nice text field subclass that gives you control over lots of the cocoa features, but I don’t see that I can control the undo except for turning it on and off?

The NSUndoManager class might be the place to start only if you want a Mac-only solution.

I have the same problem and am looking for a solution. Using a TextArea in Xojo is often meant to be adjustable by code, so getting out of sync between the built-in undo manager of the OS and setting .text or .SelText would look like a common fact…
Reinventing an undo manager would probably work, but what’s the point, then, of having a complex undo manager built in the OS (which handles a lot of things in a smart manner) if it just breaks because, say, one have used SelText maybe just once in code?

Undo managers of the OS have grown over time and are certainly solid. It’d be far more reliable to find a way to add things to them (when changing something from code) than re-inventing a new undo manager.
But I guess plugins or declares are the only ways to go…

I am using RemoteControlMBS in a utility destined to enter Unicode into apps that have the focus. If you set the focus to the TextArea and send the characters through the keyboard, you get undo automatically.

That’s a good idea, I presume.
Under 10.14 (and later) you’re getting security alerts, correct? I hardly imagine the user choosing an “Insert tag” menu item that triggers a “Do you allow access to accessibility?” for the same app… (S)he would not understand the hack.

Also, how do you deal with characters that may not be physically present on the user’s keyboard?
In my specific app, I use tags surrounded by “?” and “?”. For my own convenience, my keyboard layout is a custom one where I’ve put extra characters replacing duplicates ones (so I can write ·???·???, isn’t that nice? ;-). ). On other user’s keyboard, the “?” and “?” symbols won’t exist; RemoteControlMBS, as far as I recall, can only input keyboard keycodes, so only ones that are on the keyboard.

[quote=465172:@Arnaud Nicolet]Also, how do you deal with characters that may not be physically present on the user’s keyboard?
In my specific app, I use tags surrounded by “?” and “?”. For my own convenience, my keyboard layout is a custom one where I’ve put extra characters replacing duplicates ones (so I can write ·???·???[/quote]

Precisely, these characters are perfectly supported.

About the warning under 10.14 and 10.15, I have not tested yet, but I bet Christian did.

At any rate, it is perfectly possible to keep an undo queue within your app, effectively short circuiting the built-in mechanism, but that can be a tad of work.

Supported in strings, yes, but how can you input them using RemoteControlMBS (or corresponding API) if they aren’t in the active keyboard layout?

Perhaps he did; I haven’t seen anything related, though. Maybe he did, saw the alerts indeed show and thought it’s not worth mentioning something that has no solution…

“Tad”… do you mean like “a lot”? That’d be related to my first post: why would an OS provide a built-in undo manager if it breaks when the application modifies some text internally, without even providing a chance to handle the stack? That looks very poor and unthoughtful.
I haven’t dealt with Windows or Linux about this problem, yet. For Mac, I’ll take a look at NSUndoManager; not sure I can add things to the stack.
If Windows and Linux don’t have a similar concept (a undo manager handled by the OS), then I’ll have to decide whether to implement it or not. If not, it’ll be a big difference between platforms. If yes, I’ll have a built-in solution for Mac and a custom one for others; not practical either.
Thank you.

Have a look at the example code. You can put any character in there. There is simply no relationship with keyboard input, or current layout.

A “tad” (simple) undo seems possible by simply keeping the last ten or twenty states of the StyledText property in a queue, typically a text array. Each time the TextChange even fires, the TextArea.StyledText is appended to the array.

Undo does nothing more than to pick the latest version of StyledText on top of the array, reinstate it, and delete it from the queue.

This is a simple mechanism, and it is cross platform, without any plugin.

You are misunderstanding the nature of system undo. macOS, Windows or Linux applications who want to benefit from the OS undo must simply not modify directly the content of the control. If you do, then you must provide your own undo mechanism.

Actually, the definition (for Mac) is this:
b=RemoteControlMBS.MacPressKey(j,0)
(j being the ASCII character)

The second parameter (namely “VirtualKeyCode”) is what I’m referring to. In this example, passing 0 produces an “a” with my layout (which is indeed the keycode 0), regardless of j (I just get a series of “a” in my TextArea). From what I can see, it’s indeed related to the keyboard layout (you must provide the VirtualKeyCode, which is the “physical” code of the keyboard’s key).

[quote=465280:@Michel Bujardet]A “tad” (simple) undo seems possible by simply keeping the last ten or twenty states of the StyledText property in a queue, typically a text array. Each time the TextChange even fires, the TextArea.StyledText is appended to the array.

Undo does nothing more than to pick the latest version of StyledText on top of the array, reinstate it, and delete it from the queue.

This is a simple mechanism, and it is cross platform, without any plugin.[/quote]
As far as I remember, I already did a undo mechanism previously (years ago). I’d prefer using native undo managers, as they have grown from OS builders (years of knowledge).

OK, I’m trying…
First thing: I tried the RemoteControlMBS way under Mac OS 10.14. Bad news: the call immediately returned false and the dialog “You must enable accessibility for the application in System Preferences” showed. I enabled it and it “worked” after that (producing only “a”…). Definitively not wanting to show this dialog when the user has just chosen a menu item to insert some text…
What else to try?