Skip to content

Instantly share code, notes, and snippets.

@DanBradbury
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DanBradbury/dd203fa579f3228e37c7 to your computer and use it in GitHub Desktop.
Save DanBradbury/dd203fa579f3228e37c7 to your computer and use it in GitHub Desktop.

#Making Keyboard Tool Example Source

When all is done we will be making a small keyboard application that will listen to IO even when the screen is out of focus. To do this we will utilize the keyboard_check_direct method that GM provides and use the built in Windows Virtual Key Codes. I heard somewhere that use of these keycodes is not recommended but I think we use whatever we can to accomplish the task at hand.

##Where to get started Create a new project and and let's create a rough skeleton of what this thing might look like.

  1. Create an obect keyboardHUD with a Create Event, Draw Event, and Step Event
  2. Create room with the keyboardHUD object inside

Nothing happens when we run this as expected.

###Requirements

In order to create the effect of typing being recorded we want to keep track of every key on our keyboard and the individul key presses made. To create this effect we need a way to programatically keep track of every single key object and make sure they are being updates individually.

The plan is to use an array to hold the ON/OFF values for each "Row" of the keyboard. Since every keyboard has a different set of keys on each row we will also want to track the value of the given keys.

###Let's Begin

Here is my KBT Pure Pro 60%, which I will be using in the example

I choose to start with the first row of my keyboard because it has everything that I need to verify everything in my GM toolbelt will accomplish the goal.

I want to use the current setup we have to draw the first row of the board with all the corresponding keys.

First I want to define the * "ON/OFF values" * that will be needed to capture keystrokes.

for(i=0;i<15;i++) {
    ROW1_SELECT[i] = false;
}

I also want to define the text values for each of these keys. Right now I'll just use the skeleton and put this code into the same create code block.

ROW1[0] = "ESC";
ROW1[1] = "1";
ROW1[2] = "2";
ROW1[3] = "3";
ROW1[4] = "4";
ROW1[5] = "5";
ROW1[6] = "6";
ROW1[7] = "7";
ROW1[8] = "8";
ROW1[9] = "9";
ROW1[10] = "0";
ROW1[11] = "-";
ROW1[12] = "=";
ROW1[13] = "\";
ROW1[14] = "BK";

With these two things in place I feel pretty comforable going into the draw event with a very similar for loop to handle my entire first row. As long as the draw can stay maintainable and DRY I am happy.

Before jumping into any draw code I want to define a few constants that will help quite a bit when it comes time draw.

SMALL_KEY = 30;
MARGIN = 6;
TAB_KEY = 45;
CAP_KEY = 60;
RETURN_KEY = 75;
SHIFT_KEY = 66;
LEFT_CTRL = 36;
SPACE_BAR = 150;

We will be only using SMALL_KEY and MARGIN here but I will declare all constants needed draw the board

// setup helpers to keep track of key location
x_marker = 10;
y_marker = 30;

for(i=0;i<15;i++) {
    draw_set_color(c_black);
    draw_rectangle(x_marker, y_marker, x_marker+SMALL_KEY, y_marker+SMALL_KEY,false);
    draw_set_color(c_white); // our row selector better work :D
    if ROW1_SELECT[i]==false {
        draw_set_color(c_green);   
    }
    draw_text(x_marker,y_marker,ROW1[i]);
    x_marker+=SMALL_KEY+MARGIN;
}

If we were to run our application right now we would get the first row to draw pretty cleanly in our previously empty room.

At this point we have filled out the majority of the skeleton and just need to properly capture the keyboard input.

The step event is a simple and pattern to keep track of each switches state. It has to be repeated for every key in the row.

if keyboard_check_direct(vk_escape) {
    ROW1_SELECT[0] = true;    
} else {
    ROW1_SELECT[0] = false;
}
//..every other key after this

It is important to point out is that GM's virtual keys do not currently handle all Keyboard input. Because of this we must rely on the Windows Virtual Key definitions to perform the missing virtual keys.

For example when capturing the input for the | key I looked up the virtual key hex value 0xDC which I can pass into the first parameter of keyboard_check_direct

if keyboard_check_direct(220) {
   //..
}

Of course ord will work and is vital for the standard keys

if keyboard_check_direct(ord('1')) {
   //..
}

After filling out the rest of the step event for the row we should have a long set of conditionals for each of our keys.

if keyboard_check_direct(vk_escape) {
    ROW1_SELECT[0] = true;    
} else {
    ROW1_SELECT[0] = false;
}
if keyboard_check_direct(ord('1')) {
    ROW1_SELECT[1] = true;    
} else {
    ROW1_SELECT[1] = false;
}
if keyboard_check_direct(ord('2')) {
    ROW1_SELECT[2] = true;    
} else {
    ROW1_SELECT[2] = false;
}
if keyboard_check_direct(ord('3')) {
    ROW1_SELECT[3] = true;    
} else {
    ROW1_SELECT[3] = false;
}
if keyboard_check_direct(ord('4')) {
    ROW1_SELECT[4] = true;    
} else {
    ROW1_SELECT[4] = false;
}
if keyboard_check_direct(ord('5')) {
    ROW1_SELECT[5] = true;    
} else {
    ROW1_SELECT[5] = false;
}
if keyboard_check_direct(ord('6')) {
    ROW1_SELECT[6] = true;    
} else {
    ROW1_SELECT[6] = false;
}
if keyboard_check_direct(ord('7')) {
    ROW1_SELECT[7] = true;    
} else {
    ROW1_SELECT[7] = false;
}
if keyboard_check_direct(ord('8')) {
    ROW1_SELECT[8] = true;    
} else {
    ROW1_SELECT[8] = false;
}
if keyboard_check_direct(ord('9')) {
    ROW1_SELECT[9] = true;    
} else {
    ROW1_SELECT[9] = false;
}
if keyboard_check_direct(ord('0')) {
    ROW1_SELECT[10] = true;    
} else {
    ROW1_SELECT[10] = false;
}

if keyboard_check_direct(189) {
    ROW1_SELECT[11] = true;    
} else {
    ROW1_SELECT[11] = false;
}
if keyboard_check_direct(187) {
    ROW1_SELECT[12] = true;    
} else {
    ROW1_SELECT[12] = false;
}
if keyboard_check_direct(220) {
    ROW1_SELECT[13] = true;    
} else {
    ROW1_SELECT[13] = false;
}
if keyboard_check_direct(vk_backspace) {
    ROW1_SELECT[14] = true;    
} else {
    ROW1_SELECT[14] = false;
}

For me that is too many lines of code within a single code block. Ideally I would like to move this out into a separate script row1_check and have a call for keyboard_check in the step even along with a mouse_check to cover everything with a OOP mindset.

For now we should be able to run this and see a working first row of input! Yay!

The remaining challenge is in the setup of drawing funky rows and handling all the special characters you want to track on your keyboard. If you want to track mouse presses be sure to use the virtual keys microsoft provides :D

The rest is up to you. I challenge you to create a more DRY solution for each of the rows and customize the draw to match your specific keyboard.

If you have any questions or comments feel free to ask.

NOTE The "completed example source" shows some of the refactor steps mentioned above but there is still much that could / should be DRY'd up / refactored out into scripts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment