millis() function with a button press
Some code is shown below to illustrate a method for treating three events independently.
This code might not be completely applicable as-is, because the problem description isn't clear about what should happen when a button is pressed and about whether other events to be added to the code are like the one shown there now.  However, if you understand how it works you probably can adjust it to meet any special requirements of your application.
During each pass through the loop() routine, the code does the following for each type of event:

If the event is not currently active (as denoted by states[i] &lt; debounced), the code checks whether the event's button has been pressed (or, if its sensor has turned on).  If so, the code increments a debounce counter.  If the event's counter gets up to debounced, then the output for the event is turned on, and the event's end-time is stored in an array entry.
If the event is currently active (as denoted by states[i] &gt;= debounced), the code tests if the event's end-time has arrived; if so, it turns off the event's output bit and resets its state to 0.

The last statement in loop() busy-waits until milliseconds() returns a different value than before.  This is done so that switch-debouncing samples are taken at least a millisecond apart.  If your inputs don't need debouncing, you can remove debounce code .
/* Process three asynchronous activities: Upon a given input going
true, activate its associated output(s) for specified lengths of time.
*/

enum { nkinds=3, debounced=5 }; // # of activity kinds;  debounce-criterion
const byte outPins[nkinds] = {2, 4, 6}; // Output pin numbers
const byte inPins[nkinds]  = {3, 5, 7}; // Input pin numbers
const unsigned int actLens[nkinds] = {345, 678, 323}; // Activity lengths, ms
byte states[nkinds] = {0, 0, 0};
unsigned long actEnds[nkinds] = {0, 0, 0};

void setup() {
// Set input/output modes of pins
  for (byte i=0; i&lt;nkinds; ++i) {
    pinMode(outPins[i], OUTPUT);
    pinMode(inPins[i], INPUT);
  }
}

// Once per millisecond, for each kind of activity
// check for new beginning or deal with ongoing action
void loop() {
  unsigned long now = millis();
  for (byte i=0; i&lt;nkinds; ++i) {
    if (states[i] &lt; debounced) {  // Is activity off?
      // It's off, look for a turnon
      if (digitalRead(inPins[i])) {
        ++states[i];        // Button is closed at the moment
        // See if button has been debounced
        if (states[i] &gt;= debounced) { // If so, start its action
          digitalWrite(outPins[i], HIGH);
          actEnds[i] = now + actLens[i];
        }
      }
      else {
        states[i] = 0;      // Button is not closed at moment
      }
    }
    else { // It's on, see if end-time has arrived
      if (now &gt;= actEnds[i]) {
        digitalWrite(outPins[i], LOW); // Clear output when done
        states[i] = 0;        // Return to button-seeking state
      }
    }
  }
  while (now == millis()) {};       // Finish current millisecond
}

The code above compiles ok in the Arduino IDE but I haven't tested it on an Arduino device.
Note, larger systems with numerous events will use priority queues to implement lower-overhead versions of the same ideas.