Simulating Keypress in Div Element for Instagram DMs with JavaScript

68 views Asked by At

I'm working on a JavaScript project where I need to simulate typing into the message box in Instagram Direct Messages. However, the message box is not a standard input or textarea element but a div with contenteditable="true". My attempts to simulate keypresses on this div have been unsuccessful.

Here's what I've tried so far:

Simulating Keypress on Focused Element: I attempted to dispatch keyboard events to the currently focused element (the div message box), hoping to simulate typing. However, this method didn't work as expected. Here's the code snippet:

function typeTextLikeHuman(text, delay = 100) {
    let index = 0;
    let focusedElement = document.activeElement;

    function typeChar() {
        if (index < text.length) {
            const char = text.charAt(index);
            const keyEvent = new KeyboardEvent('keydown', {
                key: char,
                bubbles: true,
                cancelable: true,
            });
            focusedElement.dispatchEvent(keyEvent);

            // Directly append the char for contenteditable divs
            if (focusedElement.isContentEditable) {
                focusedElement.textContent += char;
            }

            index++;
            if (index < text.length) {
                setTimeout(typeChar, delay);
            }
        }
    }

    typeChar();
}

// Usage 
// Whenever im in the bot reaches the url of the direct messaging to the desirede person, i call

typeTextLikeHuman("hola"); // not working

XPath Selection: I also tried selecting the div using XPath but had no success. The XPath to the element seems correct, but document.evaluate doesn't find it.

The primary issue seems to be with the way Instagram secures the textbox from being written (indeed they dont have a textbox, so makes more confusing from where they are writing the message or how is written, thats why i went to the keypress solutions that also dont work)

Any advice or insights would be greatly appreciated!

EDIT: Tried with MutationObserver to check when the texbox div is focused, to change te content of the 'textbox' itself, changed the tex but when sending the message, its not working:

code:

const observer = new MutationObserver(mutations => {
    mutations.forEach(mutation => {
        if (mutation.addedNodes.length) {
            const editableDiv = document.querySelector('div[contenteditable]');
            if (editableDiv) {
                // Found the element, do something
                editableDiv.addEventListener('focus', () => {
                        editableDiv.innerHTML = '<p class="xat24cr xdj266r xdpxx8g" dir="ltr"><span data-lexical-text="true">kk</span></p>'; // add the span and <p> tags inside the textarea div as instagram does!
                        

                        setTimeout(function() {
                            var xpath = '/html/body/div[2]/div/div/div[2]/div/div/div[1]/div[1]/div[2]/section/div/div/div/div[1]/div/div[2]/div/div/div/div/div/div[2]/div/div/div[2]/div/div/div[3]'; // button div of 'send'
                            clickElementByXPath(xpath); // does not send anything, it only clears the textbox and nothing sent :(
                        
                        }, 5000);
                    });
            }
        }
    });
});

observer.observe(document.body, { childList: true, subtree: true });
1

There are 1 answers

6
mplungjan On

I grabbed the HTML from Instagram and made it work like this

No need for the event - however there is more going on at Instagram when the user types so it will not work at the site.

window.addEventListener('DOMContentLoaded', () => {
  document.addEventListener('click', (e) => {
    const div = e.target.closest('div[contenteditable]');
    if (div) {
      let span = div.querySelector('span');
      span.textContent = ''; // clear this test example
      typeTextLikeHuman(span, 'Your message here', 100);
    }
  });
});

function typeTextLikeHuman(tgt, text, delay = 100) {
  let index = 0;
  let tId;

  function typeChar() {
    if (index >= text.length) {
      clearInterval(tId);
      return
    }
    const char = text.charAt(index);
    tgt.textContent += char;
    index++;
  }
  tId = setInterval(typeChar, delay);
}
[role="textbox"] p {
  border: 1px solid black;
}
<div>
  <div class="x1qjc9v5 x1yvgwvq x1dqoszc x1ixjvfu xhk4uv x1ke7ulo x3jqge x1i7howy x4y8mfe x13fuv20 xu3j5b3 x1q0q8m5 x26u7qi x178xt8z xm81vs4 xso031l xy80clv x78zum5 xdt5ytf xw7yly9 xktsk01 x1yztbdb x1d52u69">
    <div class="x6s0dn4 x78zum5 x1gg8mnh x1pi30zi xlu9dua">
      <div class="x1i10hfl x6umtig x1b1mbwd xaqea5y xav7gou x9f619 xe8uvvx xdj266r x11i5rnm xat24cr x1mh8g0r x16tdsg8 x1hl2dhg xggy1nq x1a2a7pz x6s0dn4 xjbqb8w x1ejq31n xd10rxx x1sy0etr x17r0tee x1ypdohk x78zum5 xl56j7k xcdnw81 x1iorvi4 x150jy0e xjkvuk6 x1e558r4"
        role="button" tabindex="0">
        <div class="x6s0dn4 x78zum5 xdt5ytf xl56j7k"><svg aria-label="Choose an emoji" class="x1lliihq x1n2onr6 x5n08af" fill="currentColor" height="24" role="img" viewBox="0 0 24 24" width="24"><title>Choose an emoji</title><path d="M15.83 10.997a1.167 1.167 0 1 0 1.167 1.167 1.167 1.167 0 0 0-1.167-1.167Zm-6.5 1.167a1.167 1.167 0 1 0-1.166 1.167 1.167 1.167 0 0 0 1.166-1.167Zm5.163 3.24a3.406 3.406 0 0 1-4.982.007 1 1 0 1 0-1.557 1.256 5.397 5.397 0 0 0 8.09 0 1 1 0 0 0-1.55-1.263ZM12 .503a11.5 11.5 0 1 0 11.5 11.5A11.513 11.513 0 0 0 12 .503Zm0 21a9.5 9.5 0 1 1 9.5-9.5 9.51 9.51 0 0 1-9.5 9.5Z"></path></svg></div>
      </div>
      <div class="x9f619 xjbqb8w x78zum5 x168nmei x13lgxp2 x5pf9jr xo71vjh x1i64zmx xw3qccf x1uhb9sk x1plvlek xryxfnj x1iyjqo2 x2lwn1j xeuugli xdt5ytf xqjyukv x1qjc9v5 x1oa3qoh x1nhvcw1">
        <div class="x1n2onr6">
          <div aria-describedby="Message" aria-label="Message" class="xzsf02u x1a2a7pz x1n2onr6 x14wi4xw x1iyjqo2 x1gh3ibb xisnujt xeuugli x1odjw0f notranslate" contenteditable="true" role="textbox" spellcheck="true" tabindex="0" style="user-select: text; white-space: pre-wrap; word-break: break-word;"
            data-lexical-editor="true">
            <p class="xat24cr xdj266r"><span data-lexical-text="true">Text here</span></p>
          </div>
          <div class="xi81zsa x6ikm8r x10wlt62 x47corl x10l6tqk x17qophe xlyipyv x13vifvy x87ps6o xuxw1ft xh8yej3">Message...</div>
        </div>
      </div>
      <div class="x1i10hfl xjqpnuy xa49m3k xqeqjp1 x2hbi6w xdl72j9 x2lah0s xe8uvvx xdj266r xat24cr x1mh8g0r x2lwn1j xeuugli x1hl2dhg xggy1nq x1ja2u2z x1t137rt x1q0g3np x1lku1pv x1a2a7pz x6s0dn4 xjyslct x1ejq31n xd10rxx x1sy0etr x17r0tee x9f619 x1ypdohk x1f6kntn xwhw2v2 xl56j7k x17ydfre x2b8uid xlyipyv x87ps6o x14atkfc xcdnw81 x1i0vuye xjbqb8w xm3z3ea x1x8b98j x131883w x16mih1h x972fbf xcfux6l x1qhh985 xm0m39n xt7dq6l xexx8yu x4uap5 x18d9i69 xkhd6sd x1n2onr6 x1n5bzlp x173jzuc x1yc6y37 x1s85apg xfs2ol5"
        role="button" tabindex="0">Send</div>

    </div>
  </div>
</div>