OpenGL and CG Shaders – introduction

June 20th, 2009 Kristian No comments

I wanted to write a little introduction on how to setup and use the nVidia CG Toolkit and start creating some shaders for first and most OpenGL, who cares about D3D anyway?!?

Getting the toolkit

Head over to nVidias CG site and fetch the toolkit from there. Remember to get latest version!

What else do you need? You need, or preferrable want to update your graphics drivers to latest version in case you’re running on some old shit that doesn’t support different OpenGL extensions.

Getting started

Well, first I’m gonna give you an address to a beginners tutorial to CG, just so you have something to look up in, in case you were to, not that I’m saying you ever are, get stuck somewhere.

nVidia CG Tutorial book

It’s a good place to start, maybe not go through all the chapters straight away, but have a look at the first chapters and you get a general idea. That is pretty much what I’m gonna go through here too.

I already asume you are familiar with how to add library to your Visual Studio, cause we do need some of those cg librarys loaded. I will also use function oriented programming to demonstrate how this works, but theres no reason why you cant access it FROM objects so don’t be scred if you’re a OOP guru.

First, lets have a look at the CG shaders we’re gonna use. This is the simplest of the simplest ones, just to get you started. Lets have a look at the vertex shader:

vShader.cg
  1. void main( in float4 position : POSITION,
  2.    in float4 color  : COLOR,
  3.  
  4.    out float4 colorOUT  : COLOR,
  5.    out float4 positionOUT : POSITION,
  6.  
  7.    const uniform float4×4 ModelViewProj // The concatenated modelview and projection matrix
  8. )
  9. {
  10.  // Transform the current vertex from object space to clip space, since OpenGL isn't doing it for us
  11.  // as long we're using a vertex shader
  12.  positionOUT = mul(ModelViewProj, position);
  13.  
  14.  colorOUT = color;
  15. }

This is fairly simple and straight forward. What we do is pretty much just passing the color of the vertex on to the fragment shader(pixel shader). As you can see, we also need to transform the vertex position from object space to clip space, since we’re using a custom shader, OpenGL doesnt do this for us.

Now on to the fragment shader(pixel shader):

pShader.cg
  1. void main( in float4 colorIN : COLOR,
  2.    out float4 colorOUT : COLOR
  3. )
  4. {
  5.  colorOUT = float4(1.0f, .0f, .0f, 1.f);
  6. }

Now, what happens here? The only thing we do is set the current pixel to the color red(RGBA). If we wanted to make a shader that just passed the original color on, we would just go colorOUT = colorIN;. But then you wouldnt see the result of the shader.

Init

Header definitions of functions we need, and global vars used:

Global vars and function definitions
  1. CGprofile cgVertexShaderProfile; // Vertex Shader Profile
  2. CGprofile cgPixelShaderProfile; // Pixel Shader Profile
  3. CGcontext cgContext = NULL;  // A Container for cG Programs
  4. CGparameter modelViewProjMatrix; // Global for Resize
  5. CGprogram cgCurVertex, cgCurPixel, cgVertexShader,cgPixelShader;
  6.  
  7. CGprogram &CGgetVertexShader();
  8. CGprogram &CGgetFragmentShader();
  9. CGprofile &CGgetVertexProfile();
  10. CGprofile &CGgetFragmentProfile();
  11. void CGsetCurrentVertexShader(CGprogram vShader);
  12. void CGsetCurrentFragmentShader(CGprogram fShader);
  13. void CGdisableProfile(CGprofile &profile);
  14. int CGdestroy();
  15. CGprogram CGcompileVertexShader(char* fileName = NULL);
  16. CGprogram CGcompilePixelShader(char* fileName = NULL);

This is all in the source code provided, and some are explained later on, but most of them are just helper-functions to set and get current shaders. This was used in an OOP environment earlier, and its not really useful when used in such a small application like this, since the global vars are easy accessible.

First we need to initialize the cg stuff. Put this code after the opengl init block you’ve got:

InitGL()
  1.  cgContext = cgCreateContext();
  2.  if (cgContext == NULL)
  3.  {
  4.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error init", MB_OK);
  5.   return -1;
  6.  }
  7.  
  8.  cgVertexShaderProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
  9.  if (cgVertexShaderProfile == CG_PROFILE_UNKNOWN)
  10.  {
  11.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error loading profiles", MB_OK);
  12.   return -2;
  13.  }
  14.  
  15.  cgPixelShaderProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
  16.  if (cgPixelShaderProfile == CG_PROFILE_UNKNOWN)
  17.  {
  18.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error loading profiles", MB_OK);
  19.   return -2;
  20.  }
  21.  
  22.  cgGLSetOptimalOptions(cgVertexShaderProfile);
  23.  if (cgGetError())
  24.  {
  25.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error loading optimisations", MB_OK);
  26.   return -3;
  27.  }
  28.  
  29.  cgGLSetOptimalOptions(cgPixelShaderProfile);
  30.  if (cgGetError())
  31.  {
  32.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error loading optimisations", MB_OK);
  33.   return -3;
  34.  }
  35.  
  36.  cgVertexShader = CGcompileVertexShader("vShader.cg");
  37.  cgPixelShader = CGcompilePixelShader("pShader.cg");
  38.  
  39.  cgGLLoadProgram(cgVertexShader);
  40.  if(cgGetError()){
  41.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error Loading", MB_OK);
  42.   return false;
  43.  }
  44.  
  45.  cgGLLoadProgram(cgPixelShader);
  46.  if(cgGetError()){
  47.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error Loading", MB_OK);
  48.   return false;
  49.  }
  50.  
  51.  CGsetCurrentVertexShader(cgVertexShader);
  52.  CGsetCurrentFragmentShader(cgPixelShader);

First we create a context, like we usually do with OpenGL as well, just in different sense here. The next part is more interesting. This is where we set the profile used for the shaders. Why is this important? I’ll tell you, the profile you chose determine what features are available to you. It’s also important to remember that this depends on what graphics card you’ve got. You cant chose an nVidia profile for a Intel-based graphics card. And some profiles are used for DirectX and some for OpenGL. You can read more about profiles in the CG Turoial chapter 10. The basic you need to know is this:

arbvp1/arbfp1 – Basic multivendor vertex programmability (corresponding to ARB_vertex_program functionality)
vp20 – Basic NVIDIA vertex programmability (corresponding to NV_vertex_program functionality)
vp30 – Advanced NVIDIA vertex programmability (corresponding to NV_vertex_program2 functionality)

What the cgVertexShaderProfile = cgGLGetLatestProfile(CG_GL_VERTEX);/cgPixelShaderProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT); methods do for you is chose the appropriate profile for you, so you don’t have to think about finding it out yourself, and makes it easier to use the application on different hardware.

Next we have the cgGLSetOptimalOptions which sets the best options available by card, driver and selected profile.

CGcompileVertexShader/CGcompilePixelShader creates a cg program from file and are defined here:

  1. CGprogram CGcompileVertexShader(char* fileName)
  2. {
  3.  return cgCreateProgramFromFile(cgContext, CG_SOURCE, fileName, cgVertexShaderProfile, "main", 0);
  4. }
  5. CGprogram CGcompilePixelShader(char* fileName)
  6. {
  7.  return cgCreateProgramFromFile(cgContext, CG_SOURCE, fileName, cgPixelShaderProfile, "main", 0);
  8. }

The final CG method you need to run is the cgGLLoadProgram, which loads the program into the OpenGL pipeline.

Draw

Then we need to implement the actual draw methods:

DrawGLScene()
  1.  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  2.  glLoadIdentity();
  3.  
  4.  gluLookAt(-5.0, 1.0, 4.0, 0.0, 0.0, -7.0, 0.0, 1.0, 0.0);
  5.  
  6.  cgGLEnableProfile(CGgetVertexProfile());
  7.  if(cgGetError()){
  8.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error", MB_OK);
  9.   return false;
  10.  }
  11.  
  12.  cgGLBindProgram(cgVertexShader);
  13.  if(cgGetError()){
  14.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error", MB_OK);
  15.   return false;
  16.  }
  17.  
  18.  cgGLEnableProfile(CGgetFragmentProfile());
  19.  if(cgGetError()){
  20.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error", MB_OK);
  21.   return false;
  22.  }
  23.  
  24.  cgGLBindProgram(cgPixelShader);
  25.  if(cgGetError()){
  26.   MessageBox(NULL, (LPCWSTR)cgGetErrorString(cgGetError()), L"Error", MB_OK);
  27.   return false;
  28.  }
  29.  
  30.  modelViewProjMatrix = cgGetNamedParameter(CGgetVertexShader(), "ModelViewProj");
  31.  cgGLSetStateMatrixParameter(modelViewProjMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
  32.  
  33.  glPushMatrix();
  34.  
  35.  glTranslatef(-1.5f, 0.0f, -7.0f);
  36.  glRotatef(rtri, 1.0f, 0.0f, 0.0f);
  37.  cgGLSetStateMatrixParameter(modelViewProjMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
  38.  
  39.  glBegin(GL_TRIANGLES);
  40.   glColor3f(1.0f, 0.0f, 0.0f);
  41.   glVertex3f(0.0f, 1.0f, 0.0f);
  42.   glColor3f(0.0f, 1.0f, 0.0f);
  43.   glVertex3f(-1.0f, -1.0f, 0.0f);
  44.   glColor3f(0.0f, 0.0f, 1.0f);
  45.   glVertex3f(1.0f, -1.0f, 0.0f);
  46.  glEnd();
  47.  glPopMatrix();
  48.  
  49.  
  50.  CGdisableProfile(CGgetFragmentProfile());
  51.  CGdisableProfile(CGgetVertexProfile());
  52.  
  53.  
  54.  glPushMatrix();
  55.  glTranslatef(1.5f, 0.0f, -7.0f);
  56.  glRotatef(rquad, 1.0f, 0.0f, 0.0f);
  57.  glBegin(GL_QUADS);
  58.   glColor3f(1.0f, 0.0f, 0.0f);
  59.   glVertex3f( 1.0f,  1.0f,-1.0f);
  60.   glVertex3f(-1.0f,  1.0f,-1.0f);
  61.   glVertex3f(-1.0f,  1.0f, 1.0f);
  62.   glVertex3f( 1.0f,  1.0f, 1.0f);
  63.  
  64.   glColor3f(0.0f, 1.0f, 0.0f);
  65.   glVertex3f( 1.0f, -1.0f, 1.0f);
  66.   glVertex3f(-1.0f, -1.0f, 1.0f);
  67.   glVertex3f(-1.0f, -1.0f,-1.0f);
  68.   glVertex3f( 1.0f, -1.0f,-1.0f);
  69.  
  70.   glColor3f(0.0f, 0.0f, 1.0f);
  71.   glVertex3f( 1.0f,  1.0f, 1.0f);
  72.   glVertex3f(-1.0f,  1.0f, 1.0f);
  73.   glVertex3f(-1.0f, -1.0f, 1.0f);
  74.   glVertex3f( 1.0f, -1.0f, 1.0f);
  75.  
  76.   glColor3f(1.0f, 1.0f, 0.0f);
  77.   glVertex3f( 1.0f, -1.0f,-1.0f);
  78.   glVertex3f(-1.0f, -1.0f,-1.0f);
  79.   glVertex3f(-1.0f,  1.0f,-1.0f);
  80.   glVertex3f( 1.0f,  1.0f,-1.0f);
  81.  
  82.   glColor3f(1.0f, 0.0f, 1.0f);
  83.   glVertex3f(-1.0f,  1.0f, 1.0f);
  84.   glVertex3f(-1.0f,  1.0f,-1.0f);
  85.   glVertex3f(-1.0f, -1.0f,-1.0f);
  86.   glVertex3f(-1.0f, -1.0f, 1.0f);
  87.  
  88.   glColor3f(0.0f, 1.0f, 1.0f);
  89.   glVertex3f( 1.0f,  1.0f,-1.0f);
  90.   glVertex3f( 1.0f,  1.0f, 1.0f);
  91.   glVertex3f( 1.0f, -1.0f, 1.0f);
  92.   glVertex3f( 1.0f, -1.0f,-1.0f);
  93.  glEnd();
  94.  glPopMatrix();
  95.  
  96.  rtri += 0.2f;
  97.  rquad -= 0.75f;
  98.  
  99.  return true;

This is more, more and more code, but hang on, this is not too bad! Lets start from the beginning here(I’ll skipe the OpenGL stuff, I assume that if you read this, you already know some OpenGL!).

The first thing we do is now to enable and bind the cg profiles we created in the init seciton. This tells OpenGL that, hey – we want to use these shaders instead of the filthy ones you’re using at the moment! As long as these shaders are active, OpenGL uses them in the render pipeline and doesnt apply any of its own shaders. Also note that we need to specific bind both the vertex and the fragment shader.

The next thing we do is claim the variable called “ModelViewProj” and put it in our CGparameter modelViewProjMatrix variable. We will use this to put the concatenated modelview and projection matrices(CG_GL_MODELVIEW_PROJECTION_MATRIX). Why do we need this? I’ll tell you, we need it in the vertex shader to convert from object space to clip space – since OpenGL has withdrawn from every responsibility after you created your shaders. That is what the call to cgGLSetStateMatrixParameter does. See in our vertex shader that we have the following line:

  1. const uniform float4×4 ModelViewProj

This variable is what we’re setting with the cgGLSetStateMatrixParameter.

After we have done some translation and rotation, we call the cgGLSetStateMatrixParameter again to update the matrix, if not the new matrix of the triangle isn’t update(e.g. no rotation and moving of triangle).

The last thing we do(last CG related thing) is call the CGdisableProfile(), which disables the current CG profiles and falls back to the OpenGL shaders. Now our CG shaders doesn’t do anything to the rendering pipeline – all the control is back to OpenGL.

Result

When compiled, that the shaders only apply to the triangle, not the box. This is only to show that you can use multiple shader in your application without any problems. This is really handy when you use shaders for bump-mapping or different lighting effects.

Go on to nVidias page and read the tutorial and start playing around with the shaders and see how much fun you can have with it. This is a good way to see how you can affect the rendering pipeline in OpenGL.

Download the Visual Studio source code here(include the cg binaries and libraries).

Categories: 3D, Programming Tags: , , , , ,

Zend PHP Certifications

June 16th, 2009 Kristian No comments

As I hope you all know Zend is a big contributer within the PHP community. They provide debugging, server enhancement and framework to support your PHP-development. Since it has stated such a huge reputation within the PHP-circle, I figured I’ll go ahead and take a PHP5 certification. Also I don’t have any education underlying my 4 years of PHP-experience, so I thought this might be a good way to get some papers on what I already know.

So I went ahead and bought a Zend PHP5 Certification bundle package, which includes free test-exams, a book in pdf and paperback and the examination itself. The package came to about $165 USD.

I went ahead and fired up one of the test-exams too see if I actually were something of a PHP-developer at all, and luckily I passed on my first attempt. Although I did miss a fair questions, I’m not too worried since it was all related to the Soap-extension(I’ve used the nusoap library for my soap purposes, but might actually change back soon).

So there it goes, my exam is book for the 28th of August(Friday so I can hopefully go out celebrate afterwards, or drown my sorrows!). I was actually surprised of how much the certification exam coverd. Everything from design patterns, databases, security to OOP – sweet!

Have a look over at Zend Certification if you’re interested in using their services. It’s highly recommended to take a look at the framework they provide. It’s an easy and fast way for creating web-sites and services.

Categories: PHP Tags: , ,

OpenGL without the glaux library on Visual Studio(Replacement code)

June 7th, 2009 Kristian No comments

I’ve been doing a lot of 3D programming lately, mostly due to assignments at school…yey! I started googling a fair bit for the glaux library to work under Visual Studio, but found soon enough out that the library was obsolete at this stage. So I thought I would post some replacement code for the many tutorials still relaying on the glaux library.

Thanks to the boys over at NeHe Productions – give them a visit – awesome tutorials regardgin OpenGL and 3D programming. You can even download all the tutorials in PDF! Kudos boys, spent many hours on your site.

Back to the point, go fetch the library from their site or download here:

GLaux replacement code

At the moment I’m having a crack at bump mapping, fun when you realize you’ve done the wrong aproach for half a day. Gotta love CG shaders…

Categories: 3D Tags: , , ,

Chrom(ium) vs Firefox – personal opinion!

June 6th, 2009 Kristian 2 comments

So, the news about Chromium(Google Chrome for linux/mac) is out. Personal I’ve been using the development build for a month already…and theres a reason WHY!

If you’re anything like me, you pretty much have Facebook up all the time – perfect place to procrastinate from whatever you are doing. So hey, whats wrong with that? I’ll tell you whats wrong – firefox memory build up! This does apply to several version of Firefox too, I’m using the newest stable release.

Firefox and memory

What happens to firefox after having facebook up for a while, is that it’s claiming all my memory, often we’re talking about up til 40% of my 2GB memory. No this is of course after my firefox have been open for about 2 days straight!(Why would you ever need to close your browser?!). So my main thought is that the javascript engine over at mozilla labs is not doing a proper enough job freeing up memory, which sucks!

Chromium the saviour?

So, can Chromium do anything about it? Hope so, at least looking promising now. Chromium is running the V8 javascript enginge coupled with the Webkit rendering engine, which apparently go well together in a bundle;) What happens to my memory consumption when running Chromium?

I’LL TELL YOU WHAT! After running it for several days straight(without crashing or anything) it still only claim about 4% of my memory, that is 10 times as little as Firefox would claim!

Why is this? Chromium on steroids?

I still havent figured out why! The question is more; what is wrong with who? Is Firefox javascript engined really flawed, or is V8 THAT good?…or is it something else?

I’ve been planning to investigate into this at a later stage, but for now I don’t have an answer for you. As soon as Chromium develops into a full blown and stable browser I’ll do new tests with proper data and see if it still is as fast and memory efficient as it is now.

Stay tuned..

Categories: Linux, Web Tags: , , , ,

Palm Pre is coming…

June 6th, 2009 Kristian No comments

The long anticipated Palm Pre is right around the corner and figured I’ll post some links to reviews and previews! I’m guessing I’m not the only one froathing from my mouth when looking at this phone. And definatly not the only one who wish there was some more competition to the iPhone!

Personally I have big faith in the Android platform from Google, not only because I want competition, but also cause it’s open source and more freedom when it comes to developing applications.

Anywhooooo…heres some links to Palm Pre, which this post is really about!

http://i.gizmodo.com/5126702/palm-pre-preview-simply-amazing

http://www.engadget.com/2009/06/03/palm-pre-review/

Palm Pre Ad – awesome

http://gizmodo.com/5277499/palm-pre-review

Categories: Mobile Tags: , , ,

Howto: Setup Ubuntu on MacBook Air without a SuperDrive

January 18th, 2009 Kristian No comments

I looked all over the net for a guide on how to setup Ubuntu on a MacBook Air without buying the SuperDrive, but couldn’t find anything. So I hade to do it the hard way, figure it out myself!

What you need is:

  • MacBook Air
  • External drive of some kind with enough space for a Ubuntu install disk
  • Ubuntu Hardy Heron image

First step

You need to start out by creating a bootable Ubuntu disk. I’ll do a quick guide on that, if it doesn’t work, theres a lot of guides out there that could help you out. Forget it! I’ll just post a link.

https://help.ubuntu.com/community/Installation/FromUSBStick

I’de suggest to use the isotostick.sh script to do it, worked good for me.

Second step

So you’ve got a disk or a stick with a Ubuntu Hardy Heron image on it, whats next?

First we need to partition the harddrive on the MacBook Air. I suggest using the “Disk Utility” in OSX, works quick and is easy. What you need to do, is use the disk utility to create TWO additional partitions. HFS+ allows resizing, so the data on your disk will not be lost.

Just choose your main harddrive, and then the tab called “Partition“.

Then add 2 new partitions

Choose the second partition on the left side

Choose the tab called “Erase

Format the disk as MS-DOS, shouldn’t take long.

Now we’ve got 2 extra partitions – let’s move on to the fun stuff!

Our next task would be to copy the external disk/stick to the second partition on your system. This should be named disk0s3(HAVE TO CHECK). We need to copy it byte by byte, so the whole boot sector and stuff is added as well.

First you have to figure out what the external disks address is, I presume it is /dev/disk1s0, then run this command in a terminal window:

dd if=/dev/disk1s0 of=/dev/disk0s3

This could take a while, depending on your harddrive and external drives size. Go make a cup of coffee, or order som food.

When this is done, we can move on to even more exciting stuff!

Step three – booting and installing

First things first!

Before you start installing anything, you should install rEFit.This i a bootloader so you can choose between OSX and Ubuntu AND it helps you start the Ubuntu installation. It should be a fairly easy installation to do, just follow the guide on the webpage.

When that is done, we can start thinking about Ubuntu again. When you boot now, rEFit shoud come up so you can choose between OSX and a Windows-ish like icon. Before you do anything, choose the icon underneath which is called “Setup partitions” or something like that.

This should ask you a yes or no question, where you clearly answer YES. What it does, is to activate your fat-partition and makes it bootable.

I now recommend a reboot.

When you now get to the rEFit menu again, choose the windows-ish icon. THIS SHOULD START YOUR UBUNTU INSTALLATION IF EVERYTHING WENT WELL.

Step four – Installing Ubuntu

I presume that this step is know to everyone by know. Just a couple of reminders for the installation.

Rember to NOT touch the partition which holds the Ubuntu installation files!

You can use that partition as a /home mount later if you want, but for now you need it to install Ubuntu.

Step five – Complete the shit

Now your installation should be done, and on your next reboot, rEFit should show a nice linux logo and a not so nice OSX logo. This means it recognize theres a linux partition on the system. So far so good.

Try booting your new linux partition!

It should now work, if not, try to shutdown your computer and then try again. If it still doesn’t work – try post a comment or something, could be something wrong with my guide.

What works and what doesn’t?

The main concerns on the MacBook Air is the following:

  • iSight camera
  • Wireless card
  • Touchpad
  • One mousebutton
  • FN key and associated keys

iSight camera

The iSight camera should work out of the box! Simply install the package called “cheese” and try it out

Wireless card

Here you need some additional stuff. Go to your closest Hardy Heron repository and download the ndiswrapper packages(ndiswrapper-common, ndiswrapper-utils) and also get the “unrar” package.

Transfere these packages to your new Ubuntu installation using your external harddrive and install them. Also transfer over the drivers for your wireless card from your FIRST OSX CD. The drivers are located in /boot camp/drivers/broadcom. And the file you are looking for is broadcomxpinstaller.exe.

Use unrar to extract the broadcomxpinstaller.exe with this command:

unrar x broadcomxpinstaller.exe

You should now have a .inf file named bcmwl5.inf. Execute the following commands:

sudo ndiswrapper -i bcmwl5.inf

sudo ndiswrapper -l

sudo ndiswrapper -m

sudo modprobe ndiswrapper

IMPORTANT! You may already have loaded the ssb-module – YOU NEED TO REMOVE IT!

The ssb module stops the ndiswrapper from accessing the wireless card.

Remove the ssb module using this command:

sudo rmmod ssb

sudo rmmod ndiswrapper

sudo modprobe ndiswrapper

Then add ndiswrapper to /etc/modules:

sudo gedit /etc/modules

That should do it! You might need to blacklist the ssb module, or remove it on every reboot – up to you;)

Touchpad and right click

One thing you might not be used to, it the one button mouse on the MacBook Air. To work around this problem, install the package called “mouseemu”.

After installation, add these lines to /etc/init.d/mouseemu :

MID_CLICK=”-middle 125 272″ # Command key + mouse click

RIGHT_CLICK=”-right 29 272″ # Control key + mouse click

#SCROLL=”-scroll 56″ # Alt key + mouse movement

SCROLL=”-scroll 125″ #Scrolls while holding Command button

TYPING_BLOCK=”-typing-block 300″ # block mouse for 300ms after a keypress

After edting this file, remember to restart the service:

/etc/init.d/mouseemu restart

Feel free to tweak this settings as you like. You can also use the “showkey” command to figure out keycodes.

That should be about it!

Feel free to leave comments and suggestions – this guide is not flawless, so any feedback is appricated, thanks! :)

Categories: Linux Tags: , , ,