emulate SHIFT key on Arduino Micro + CD4021BE shiftin register

Hi all (beginner here), I have a problem with creating key combinations using a simple ShiftIn circuit with Arduino Micro and CD4021BE - arranged like in the official tutorial

Now (please see attached code) is set up to simply write a lower case letter with a press of a button:

#include <Keyboard.h>

int dataPin = 9;
int clockPin = 7;
int latchPin = 8;

unsigned long last_press = 0;
unsigned long last_key_press = 0;

char* letters[] ={"abcdefgh"};


int num_chars = 8;
int num_registers = 1;
byte button_states[] = {0x00,0x00,0x00,0x00};  //01001000
int cursor_index = 0;
int char_index = 0;
char cur_char = 'X';

void setup() {
  Serial.begin(9600);
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT); 
  pinMode(dataPin, INPUT);
  Keyboard.begin();

}

void loop() {
  if (millis() - last_key_press > 350) read_keyboard();
  delay(50);
}


void read_keyboard(){
  //set it to 0 to transmit data serially  
  digitalWrite(latchPin,LOW);
  //while the shift register is in serial mode
  //collect each shift register into a byte
  //the register attached to the chip comes in first 
  for (int i = 0; i < num_registers; i++){
    button_states[i] = shiftIn(dataPin, clockPin);
  }
  boolean something_in = false;
  for (int i = 0; i < num_registers; i++){    
    something_in = translate_buttons_2_keys(button_states[i], letters[i]);
    if (something_in) last_key_press = millis(); 
  }
  digitalWrite(latchPin,HIGH);
}

boolean translate_buttons_2_keys(byte buttons, char* keys){
  for(int i = 0 ; i < 8; i++){
     if ( (1 << i) & buttons ){
       cur_char = keys[i];
       Keyboard.print(keys[i]);
       char_index++;
       return true;
     }     
  }
 return false; 
}
byte shiftIn(int myDataPin, int myClockPin) { 
  int i;
  int temp = 0;
  int pinState;
  byte myDataIn = 0;

  pinMode(myClockPin, OUTPUT);
  pinMode(myDataPin, INPUT);

  for (i=7; i>=0; i--)
  {
    digitalWrite(myClockPin, 0);
    delayMicroseconds(20);
    temp = digitalRead(myDataPin);
    if (temp) {
      pinState = 1;
      myDataIn = myDataIn | (1 << i);
    }
    else {
      pinState = 0;
    }
    digitalWrite(myClockPin, 1);
  }
  return myDataIn;
}

but I want to emulate the SHIFT key (or other non-character keys) - so while this key is pressed, in combination with these lower case letters, the corresponding upper case (or a punctuation) character to appear.

I tried to use byte instead of char (so I can put the hexa code for the Left Shift key) but it returned me random characters...

I managed to do this using individual digital pins:

#include <Keyboard.h>
#define KEY_LEFT_SHIFT 0x81
int buttonPin = 2;  
int buttonPin2 = 3;

void setup()
{
  pinMode(buttonPin, INPUT);  
  digitalWrite(buttonPin, HIGH);  
    pinMode(buttonPin2, INPUT);  
  digitalWrite(buttonPin2, HIGH);  
}

void loop()
{
  if (digitalRead(buttonPin) == 0)  
  {
  Keyboard.press(KEY_LEFT_SHIFT);
  delay(250);
      
  }
    if (digitalRead(buttonPin2) == 0)
  {
  Keyboard.press('n');
  Keyboard.release('n');
    delay(250);  
  }
  if(digitalRead(buttonPin)&&digitalRead(buttonPin2)==true)
{
Keyboard.releaseAll();
}
}

but can't figure out how to do it with the shift register. Please help me to find this solution, it really bugs me, couldn't find nothing on internet on this specific matter.

Is even possible to have combination of keys (multi-press) by using the CD4021BE shift register?

void loop() {
  if (millis() - last_key_press > 350) read_keyboard();
  delay(50);
}

That delay() is stupid. Why do you care how many times loop() iterates and does nothing?

  if (digitalRead(buttonPin) == 0)  
    if (digitalRead(buttonPin2) == 0)
  if(digitalRead(buttonPin)&&digitalRead(buttonPin2)==true)

Make up your mind. Either digitalRead() returns a numeric value (it does) or it returns a boolean (it does not). Don't mix types like that.

so while this key is pressed

We can't see what "key" you are pointing to.

I tried to use byte instead of char (so I can put the hexa code for the Left Shift key) but it returned me random characters...

Why did you think it was necessary to change types? A char holds a binary value in the range -128 to 127. The Keyboard library only supports values from 0 to 127.

but can't figure out how to do it with the shift register.

I don't think you can do "it" with a shift register. All those pins are going to hurt.

5th grade comments aside, WHAT can't you do with a shift register? There is NOTHING in your code that admits the existence of a shift register.

Well, those pins can be removed, you know... :slight_smile:

Joke aside, what I'm trying to achieve is either so simple or not possible, giving the fact I didn't find an 'on spot' solution around.

I want to do a custom keyboard that have SHIFT, CTRL, ALT and all the non-character keys functional, using at least one shift register.
For example I have one button that I have to make it behave like SHIFT key, and the 7 others like character keys, all these wrapped in a shift register CD4021BE.

The code I took is from a custom keyboard that is using the same principle but without these non-character keys/ or multi-pressing/ keys combination function
http://lucidtronix.com/tutorials/15

So, where is the code that reads the switches connected to the shift register? Where is the schematic showing how the switches are connected?

The schematic is unchanged from my first post reference:

I have a problem with creating key combinations using a simple ShiftIn circuit with Arduino Micro and CD4021BE - arranged like in the official tutorial

https://www.arduino.cc/en/Tutorial/ShiftIn

I'm not a professional programmer, but I guess the code that verify the switches is:

boolean translate_buttons_2_keys(byte buttons, char* keys){
  for(int i = 0 ; i < 8; i++){
     if ( (1 << i) & buttons ){
       cur_char = keys[i];
       Keyboard.print(keys[i]);
       char_index++;
       return true;
     }     
  }
 return false;
}

reading the keys based on this:

char* letters[] ={"abcdefgh"};

Did a little research, and I was thinking if is possible to make an integer array and with hexadecimals values like this ( where 0x81 is the SHIFT key)? :

int letters[] = { 0x81, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67 }; // { KEY_LEFT_SHIFT, a, b, c, d, e, f, g }

Would it work if I just replace char* with int?

Would it work if I just replace char* with int?

Maybe. But, I doubt it.

What I think you want to do is Keyboard.print() the value as-is from the array if the "shift key" is not pressed, and after adding ('A' - 'a') to the value in the array if it is pressed.

  for(int i = 0 ; i < 8; i++){
     if ( (1 << i) & buttons ){
       cur_char = keys[i];
       if(shiftKeyPressed())
          cur_char += 'A' - 'a';
       Keyboard.print(cur_char);

I see no reason for cur_char or char_index in the original code, but having cur_char makes it easy to change the character that is output. char_index is still useless (as far as that snippet is concerned).

All you have to do is write the shiftKeyPressed() function to return true or false, depending on whether or not the "shift key" is pressed.