Page 1 of 1

Read one keypress at a time from STDIN [UPDATE]

Posted: Fri Dec 17, 2004 5:57 pm
by npeelman
Has anyone come up with a solution for this? I'm not sure why it should be so difficult.

Thanks,
Norm

Re: Read one keypress at a time from STDIN without <retur

Posted: Sat Dec 18, 2004 3:46 am
by Weirdan
npeelman wrote:I'm not sure why it should be so difficult.
Because php uses stream oriented IO. You might want to experiment with ncurses extension, particularly with [php_man]ncurses_cbreak[/php_man] function.

Re: Read one keypress at a time from STDIN without <retur

Posted: Sat Dec 18, 2004 10:33 am
by npeelman
Weirdan wrote:
npeelman wrote:I'm not sure why it should be so difficult.
Because php uses stream oriented IO. You might want to experiment with ncurses extension, particularly with [php_man]ncurses_cbreak[/php_man] function.
Currently working on a solution to this, actually having some success. Details to follow (maybe).

Norm

Re: Read one keypress at a time from STDIN [UPDATE!]

Posted: Sun Dec 19, 2004 7:58 am
by npeelman
npeelman wrote:
Weirdan wrote:
npeelman wrote:I'm not sure why it should be so difficult.
Because php uses stream oriented IO. You might want to experiment with ncurses extension, particularly with [php_man]ncurses_cbreak[/php_man] function.
Currently working on a solution to this, actually having some success. Details to follow (maybe).

Norm
Ok,

Current point of solution. There seems to be three options:
1) ncurses/ or derivative (Windows compatible ???)
2) external DOS commands
3) system calls (win32.api via FFI - http://pecl.php.net/package/ffi )

#1, i'm really not into/up to speed 'building/makeing' on Win32 or Linux so that's out for me.
#2 is doable to a point (and actually not -much- different from #3.
#3 is working now with a few quirks.

Currently, I can receive keystrokes from the keyboard one keypress at a time, BUT I am receiving ALL keypresses system wide (for any/all applications). I am getting hung up on the window active/focus functions. If this would be the only program running I guess it's ok, if you would be using other programs at the same time then anytime this program is expecting keyboard input it would receive keystrokes while they are typed in the other applications. If anyone has any knowlege of working with PHP/Win32 api/FFI functions it would be helpfull. And if anyone is interested in the details they can email me at npeelman@cfl.rr.com

Norm

Re: Read one keypress at a time from STDIN [UPDATE!]

Posted: Mon Dec 20, 2004 2:50 am
by Weirdan
npeelman wrote: 1) ncurses/ or derivative (Windows compatible ???)
Actually yes :) Cygwin compatible.
3) system calls (win32.api via FFI - http://pecl.php.net/package/ffi )
<...skipped...>
Currently, I can receive keystrokes from the keyboard one keypress at a time, BUT I am receiving ALL keypresses system wide (for any/all applications).
Post you code, we might be able to help you. To my understanding you should be able to use functions of win32 console subsystem (e.g. ReadConsoleInputA) without much problems.

Re: Read one keypress at a time from STDIN [UPDATE!]

Posted: Mon Dec 20, 2004 5:02 am
by npeelman
Weirdan wrote:
npeelman wrote: 1) ncurses/ or derivative (Windows compatible ???)
Actually yes :) Cygwin compatible.
3) system calls (win32.api via FFI - http://pecl.php.net/package/ffi )
<...skipped...>
Currently, I can receive keystrokes from the keyboard one keypress at a time, BUT I am receiving ALL keypresses system wide (for any/all applications).
Post you code, we might be able to help you. To my understanding you should be able to use functions of win32 console subsystem (e.g. ReadConsoleInputA) without much problems.
I was hoping to come up with a simple solution that would be PHP only, or in otherwords PHP and something that people already have on their computer (namely the OS). My real problem at this point is my knowlege of C/C++ style programming conventions and how they relate to the FFI package. I'm not sure if the FFI package supports ALL C/C++ variable types and I would have to create alot of structs to work with the 'window'ing message que's, etc. I was hoping that I could simply pay attention to whether my 'shell' window had focus or not and only process the keystrokes if it does, but that's not quite working either.
I'll post some code this evening when i've had a chance to clran it up a bit. It's a mess right now.

Norm

Re: Read one keypress at a time from STDIN [UPDATE!]

Posted: Tue Dec 21, 2004 9:26 pm
by npeelman
npeelman wrote:
Weirdan wrote:
npeelman wrote: 1) ncurses/ or derivative (Windows compatible ???)
Actually yes :) Cygwin compatible.
3) system calls (win32.api via FFI - http://pecl.php.net/package/ffi )
<...skipped...>
Currently, I can receive keystrokes from the keyboard one keypress at a time, BUT I am receiving ALL keypresses system wide (for any/all applications).
Post you code, we might be able to help you. To my understanding you should be able to use functions of win32 console subsystem (e.g. ReadConsoleInputA) without much problems.
I was hoping to come up with a simple solution that would be PHP only, or in otherwords PHP and something that people already have on their computer (namely the OS). My real problem at this point is my knowlege of C/C++ style programming conventions and how they relate to the FFI package. I'm not sure if the FFI package supports ALL C/C++ variable types and I would have to create alot of structs to work with the 'window'ing message que's, etc. I was hoping that I could simply pay attention to whether my 'shell' window had focus or not and only process the keystrokes if it does, but that's not quite working either.
I'll post some code this evening when i've had a chance to clran it up a bit. It's a mess right now.

Norm

Code: Select all

<?php

//CONSTANTS

$win32 = <<<EOD
[lib='user32.dll'] int BlockInput(int fBlockIt);
[lib='user32.dll'] int BringWindowToTop(int hWnd);
[lib='user32.dll'] int EnableWindow(int hWnd, int bEnable);
[lib='user32.dll'] int GetShellWindow();
[lib='user32.dll'] int GetFocus();
[lib='user32.dll'] int GetForegroundWindow();
[lib='user32.dll'] int GetActiveWindow(int hWnd);
[lib='user32.dll'] int GetAsyncKeyState(int v_key);
[lib='user32.dll'] int GetKeyState(int v_key);
[lib='user32.dll'] int GetKeyNameText(int lparam, int *lpstring, int nsize);
[lib='user32.dll'] int GetKeyboardState(char* lpkeystate);
[lib='user32.dll'] int GetTopWindow(int hWnd);
[lib='user32.dll'] int LockSetForegroundWindow(int uLockCode);
[lib='user32.dll'] int SetForegroundWindow(int hWnd);
[lib='user32.dll'] int SetFocus(int hWnd);
[lib='kernel32.dll'] int GetLastError();
EOD;

/*
GetKeyState -> For A-Z,a-z, and 0-9 set v_key == ascii-code for desired key.
               else use virtual key code
*/

$key_in = 0;
$key = '';
$kb_array = str_repeat('0',256);
$kb_array2 = $kb_array;
//$accept = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ".chr(13).chr(27);

// $accept = all key codes
for($loop = 0; $loop <= 256; $loop++)
{
   @$accept .= chr($loop);
}

$kb_focus = 0;
$win_handle = 0;
$foreground_handle = 0;

$console32 = new ffi($win32);

$win_handle = $console32->GetShellWindow();
if ($win_handle == NULL)
{
   echo "Could not get handle to shell!\n\r";
   exit;
}
else
{
   echo "Got handle to shell window!\n\r";
   $old_focus = $console32->GetActiveWindow($win_handle);
   if ($old_focus == NULL)
   {
      echo "win_handle focus not set!\n\r";
      //exit;
   }


   if ($console32->BringWindowToTop($win_handle) != 0)
   {
      echo "Window brought to top (should be active)\n\r";
      $top_handle = $console32->GetTopWindow(NULL);
      
   }
   else
   {
      echo "Window not brought to top!\n\r";
      exit;
   }

   if ($console32->SetForegroundWindow($win_handle) != 0)
   {
      echo "Window is now foregound window!\n\r";
      $foreground_handle = $console32->GetForegroundWindow();
      if ($foreground_handle == NULL)
      {
         echo "Could not get handle to foreground window!\n\r";
         exit;
      }
      else
      {
         echo "Got handle to foreground window!\n\r";
      }
   }
}

if ($win_handle != $foreground_handle)
{
   echo "Not the same handle!\n\r";
   //exit;
}
else
{
   echo "The same handle!\n\r";
   $go = 1;
}
echo "Window handles checked OK! \n\r";




//while ($win_handle == $console32->GetForegroundWindow())
//{
//   echo "Focused!\n\r";
//   sleep(1);
//}
//echo "Not focused!";

//exit;

//$go = 1;
$char = 0;
$tmp = '';
$extended = 0;

if ($go = 1)
{
   echo "Will accept everything, even mouse - ESC to quit\n\r";
   while(true)
   {
      /* this really doesn't work right
      if ($win_handle == $console32->GetForegroundWindow())
      {
         echo "Has focus!\n\r";
      }
      else
      {
         echo "Lost focus!\n\r";
      }
      */
      $key_in = $console32->GetAsyncKeyState(ord($accept[$char])); 

      if ($key_in != 0)
      {
         // we have a key press

      if ($char >= 112 && $char <= 124)
      {
         echo "\n\rFUNCTION KEY\n\r";
         continue;
      } 

         $key = $accept[$char];
         /* alternate Fkey code
         if ($key >= 'p' && $key <= '{')
         {
            $extended = 1;
         }
         if ($extended == 1)
         {
            echo "\n\rFunction key ";
            switch (ord($key))
            {
               case 112:
               {
                  echo 'F1';
                  break;
               }
               case 113:
               {
                  echo 'F2';
                  break;
               }
               default:
               {
                  echo 'F?';
                  break;
               }
            }
            echo " pressed!\n\r";
            $extended = 0;
         }               
         */


         if ($key == chr(27))
         {
            echo "\n\r 'ESC' was pressed!\n\r";
            echo "\n\r\n\rYou typed -> \n\r $tmp";
            exit;
         }
         else
         {
            echo $key;
	   //echo $key.ord($key);
            $tmp .= $key;
         }
      }  

      if ($char == (strlen($accept) - 1))
      {
         $char = -1;
      }

      usleep(500);

      $char++;
   }
}


/* this sortof works - keystate rotates through all values

$key_test = $console32->GetKeyState(65);
echo "The 'A' key is ";
switch ($key_test)
{
   case -127:
   {
      echo "pressed";
      break;
   }
   case -128:
   {
      echo "pressed w/shift";
      break;
   }
   default:
   {
      echo "up";
   }
}
*/


/* this just doesn't work at all as $kb_array never gets updated.
for($loop = 0; $loop <= 10000; $loop++)
{
   $result = $console32->GetKeyboardState($kb_array);
   echo "$kb_array \n\r";
   echo "\n\rResult = $result\n\r";
   echo $console32->GetLastError()."\n\r";

   for($loop2 = 0; $loop2 <= 255; $loop2++)
   {
      if ($kb_array[$loop2] != 0)
      {
         echo "Key pressed!";
         exit;
      }
      else
      {
         echo ord($kb_array[$loop2])."\n\r";
      }
   }
usleep(10000);
}
*/
?>
This code is ugly for sure, i'm just trying to get the system calls working. The window focus really doesn't work properly. I really must find a way to get ahold of the shells' message que but some of the more advanced system calls require certain structures to be set up and I don't know if FFI can handle all the different variable types. EXERCISE EXTREME CAUTION as all keypresses are caught.