Encoder direction without INT 0 or 1

This is probably simple, but I'm trying to sense the direction of turn for a rotary encoder (cheap KY-040 which has pull-ups on it). I can do it easily if the external interrupt vectors on INT0 or INT1 are available, but pins 2 and 3 are tied up. Pins 10 and 11 are free for any use and those are the pins I'm using, but I cannot get a direction of turn. I'd post the code, but I don't have anything that works. I had one that gave multiple strobes (e.g., CW and CCW), but of course I can't even find that one now. Any ideas would be appreciated.

This code displays multiple strobes, but the first one is usually correct in that it says whether the encoder is rotating CW or CCW. It would be nice, however, to get rid of the secondary pulse chain.

// PinChangeIntExample, version 1.1 Sun Jan 15 06:24:19 CST 2012
// See the Wiki at http://code.google.com/p/arduino-pinchangeint/wiki for more information.
//-------- define these in your sketch, if applicable ----------------------------------------------------------
// You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts
// on any one or two of the three ports.  If only a single port remains, the handler will be declared inline
// reducing the size and latency of the handler.
//#define NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts
#define NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts
#define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts
// if there is only one PCInt vector in use the code can be inlined
// reducing latency and code size
// define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation.
#define       DISABLE_PCINT_MULTI_SERVICE
//-------- define the above in your sketch, if applicable ------------------------------------------------------
#include <PinChangeInt.h>

// This example demonstrates a configuration of 3 interrupting pins and 2 interrupt functions.
// All interrupts are serviced immediately, but one of the pins (pin 4) will show you immediately
// on the Terminal.  The other function connected to 2 pins sets an array member that is queried in loop().
// You can then query the array at your leisure.
// This makes loop timing non-critical.

// Add more Pins at your leisure.
// For the Analog Input pins used as digital input pins, and you can use 14, 15, 16, etc.
// or you can use A0, A1, A2, etc. (the Arduino code comes with #define's
// for the Analog Input pins and will properly recognize e.g., pinMode(A0, INPUT);
#define PIN1 10
#define PIN2 11
#define PIN3 12

uint8_t latest_interrupted_pin;
uint8_t interrupt_count[20] = {0}; // 20 possible arduino pins
volatile int dir;

void quicfunc() {
  latest_interrupted_pin = PCintPort::arduinoPin;
  if (latest_interrupted_pin == PIN1) {
    Serial.println("CW");
    latest_interrupted_pin = 0;
  } else {
    if (latest_interrupted_pin == PIN2) {
      Serial.println("CCW");
      latest_interrupted_pin = 0;
    }
  }
}

// You can assign any number of functions to any number of pins.
// How cool is that?
void pin3func() {
  Serial.print("Pin "); Serial.print(PIN3, DEC); Serial.println("!");
}

void setup() {
  pinMode(PIN1, INPUT); digitalWrite(PIN1, HIGH);
  PCintPort::attachInterrupt(PIN1, &quicfunc, FALLING);  // add more attachInterrupt code as required
  pinMode(PIN2, INPUT); digitalWrite(PIN2, HIGH);
  PCintPort::attachInterrupt(PIN2, &quicfunc, FALLING);
  pinMode(PIN3, INPUT); digitalWrite(PIN3, HIGH);
  PCintPort::attachInterrupt(PIN3, &pin3func, CHANGE);
  Serial.begin(115200);
  Serial.println("---------------------------------------");
}

uint8_t i;
void loop() {
  uint8_t count;
  if (latest_interrupted_pin != 0) {
    Serial.print("last pin = ");
    Serial.println(latest_interrupted_pin);
    latest_interrupted_pin = 0;
  }
  //  Serial.print(".");
  //  delay(1000);
  /*
    for (i=0; i < 20; i++) {
    if (interrupt_count[i] != 0) {
      count=interrupt_count[i];
      interrupt_count[i]=0;
      Serial.print("Count for pin ");
      if (i < 14) {
        Serial.print("D");
        Serial.print(i, DEC);
      } else {
        Serial.print("A");
        Serial.print(i-14, DEC);
      }
      Serial.print(" is ");
      Serial.println(count, DEC);
    }
    }
  */
}

Or just look for a rotary encoder library that doesn't use the external interrupts. Using the external interrupts is to me like firing a bazooka at a mosquito...

A pot-style rotary encoder is a physically slow device and interrupts are probably not needed
if your system is well structured and doesn't hog the processor for too long in any one place.

If the encoder were a high resolution motor shaft encoder interrupts are necessary (and sometimes
not fast enough!).

General quadrature encoder libraries tend to use interrupts so they can be used for either type.

True, I was indeed only referring to user input rotary encoders.

Here is a sketch I which polls pins 10 and 11, and uses the Bounce2 library to debounce, which is usually needed on a KY040. It's got alot of educational features incorporated, but it can be a model for polled and debounced mechanical encoder reading. Reverse the pins, or wires, if CW and CCw are not right.

//Based on code from: http://bildr.org/2012/08/rotary-encoder-arduino/
//uses quadrature bit pattern from current and previous reading

//Changes
//Polled rather than interrupts
//Added start up position check to make index +1/-1 from first move
//Add bounce2 and debounce of digitalReads

#define encoderPinA  10   
#define encoderPinB  11 
#define buttonPin 5

#include <Bounce2.h>
// Instantiate three Bounce objects for all pins with digitalRead
Bounce debouncerA = Bounce(); 
Bounce debouncerB = Bounce(); 
Bounce debouncer5 = Bounce();

int lastEncoded = 0;
int encoderValue = 0;
int lastencoderValue = 0;

void setup() {
  Serial.begin (115200);

  pinMode(encoderPinA, INPUT_PULLUP); 
  pinMode(encoderPinB, INPUT_PULLUP);
  pinMode(buttonPin, INPUT_PULLUP);

  debouncerA.attach(encoderPinA);
  debouncerA.interval(5);
  debouncerB.attach(encoderPinB);
  debouncerB.interval(5);
  debouncer5.attach(buttonPin);
  debouncer5.interval(5);

  //get starting position
  debouncerA.update();
  debouncerB.update();

  int lastMSB = debouncerA.read(); 
  int lastLSB = debouncerB.read(); 

  Serial.print("Starting Position AB  " );
  Serial.print(lastMSB);
  Serial.println(lastLSB);

  //let start be lastEncoded so will index on first click
  lastEncoded = (lastMSB << 1) |lastLSB;

}

void loop(){ 

  debouncerA.update();
  debouncerB.update();

  int MSB = debouncerA.read();//MSB = most significant bit
  int LSB = debouncerB.read();//LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin values to single number

  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  //test against quadrature patterns CW and CCW
  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time

  if(encoderValue != lastencoderValue){
    Serial.print("Index:  ");
    Serial.print(encoderValue);
    Serial.print('\t');

    Serial.print("Old-New AB Pattern:  ");

    for (int i = 3; i >= 0; i-- )
    {
      Serial.print((sum >> i) & 0X01);//shift and select first bit
    }

    Serial.println();

    lastencoderValue=encoderValue;
  }

  //reset index
  debouncer5.update();
  if(debouncer5.read()==LOW){
    encoderValue=0;
  }

}

Thanks to all. I should have mentioned that it was being rotated by a user so an interrupt really isn't necessary.