expect and proc_open() are both going to use a pipe to provide stdin, so that won't make any difference. Since stdin is just a file handle, regardless of whether it's interactive or redirected, you need to cause isatty to think that the handle is a TTY when it's a pipe.
The only way I can think of to do this, without going and looking at the source for multiple implementations of the C standard library is to use LD_PRELOAD to override the default implementation of isatty with a special version that returns 1 for the particular handle that you're using as stdin.
Update:
Looks like implementations of the C standard library use ioctl to store a handle or pointer to terminal information with the file handle, and if you fake a TTY by setting a fake pointer using an ioctl code, anyone who tries to do TTY-specific stuff with that handle will likely crash.
e.g., libc uses tcgetattr which uses ioctl(TCGETS) to store a termios structure, where libbc uses gtty which uses ioctl(TIOCGETP) to store a sgttyb structure.
So I think you could trick libc by doing this:
ioctl(p, TCSETS, 42);
You might be able to trick one or two implementations, but it won't be portable, and you'll have to be sure the program that's using the handle doesn't do anything TTY-related other than isatty.