Alternate 'navigation'

19 views
Skip to first unread message

Nazri

unread,
Dec 3, 2008, 12:56:56 AM12/3/08
to keynav-users
Hello Jordan,

Greetings from Malaysia.

Thanks for writing keynav. It's awesome! I just discovered it
yesterday so pardon my ignorance on its full functionality.

I was thinking similar tool the other day but with a slightly
different (better, IMHO) approach to zooming in on the area to click:

Upon activation the initial grid is like 10 columns by 20 rows. The
rows are labeled from A-Z while the columns are labeled from 0-9.

Then you locate two things:

1. The button/ballpark where you'd like to click the mouse on (let's
call this target)
2. The grid crossing closest to the button/ballpark (let's call this
the nearest crosshair).

Then you do this:

Use h/j/k/l to REDUCE the width/height of the cells from left/down/up/
right direction respectively, about 1 percent or so each time, so that
the nearest crosshair moves closer to the target. Repeat this until it
is inside the target and then you can issue the click/mousedown
command.

Each grid crossing is labeled for easy identification, for example the
area near the grid at column 3, row C (C3) would look somewhat like
this:

+-----------+-----------+---
| | |
|2 B|3 B|4
+-----------+-----------+---
| | |
|2 C|3 C|4
+-----------+-----------+---
| | |
|2 D|3 D|4
+-----------+-----------+---

(Hopefully the ascii art above shows up right in your MUA)

We can then hit some key combination (for example, comma-c-3) to
activate the mouse click there.

Attached is a throw-away patch at the above (because I suck at Xlib
programming). It's just to give you an idea of the "zooming in" idea.
The labelling is not implemented, I just did a one-liner XDrawString
just to experiment with it, neither does the keybinding part.

What do you guys think?

Nazri.

throwaway patch follows..

diff --git a/keynav.c b/keynav.c
index cc37fe7..029e8f8 100644
--- a/keynav.c
+++ b/keynav.c
@@ -81,7 +81,7 @@ void cmd_start(char *args);
void cmd_warp(char *args);

void update();
-void drawborderline(struct wininfo *info, Window win, GC gc,
XRectangle *clip);
+void drawborderline(struct wininfo *info, Window win, GC gc,
XRectangle *clip, char id);
void handle_keypress(XKeyEvent *e);
void handle_commands(char *commands);
void parse_config();
@@ -412,7 +412,7 @@ GC creategc(Window win) {

void drawgrid(Window win, struct wininfo *info, int apply_clip) {
GC gc;
- XRectangle clip[30];
+ XRectangle clip[32];
int idx = 0;
Colormap colormap;
XColor red, unused_xcolor;
@@ -500,7 +500,7 @@ void drawgrid(Window win, struct wininfo *info,
int apply_clip) {
}

for (i = 0; i < idx; i++) {
- drawborderline(info, win, gc, &(clip[i]));
+ drawborderline(info, win, gc, &(clip[i]), 'a' + i);
}
}

@@ -513,8 +513,8 @@ void cmd_start(char *args) {
wininfo.h = rootattr.height;

/* Default start with 4 cells, 2x2 */
- wininfo.grid_x = 2;
- wininfo.grid_y = 2;
+ wininfo.grid_x = 20;
+ wininfo.grid_y = 10;

wininfo.border_thickness = 5;
wininfo.pen_size = 1;
@@ -586,28 +586,28 @@ void cmd_quit(char *args) {
void cmd_cut_up(char *args) {
if (appstate & STATE_ACTIVE == 0)
return;
- wininfo.h = percent_of(wininfo.h, args, .5);
+ wininfo.h = percent_of(wininfo.h, args, .99);
}

void cmd_cut_down(char *args) {
int orig = wininfo.h;
if (appstate & STATE_ACTIVE == 0)
return;
- wininfo.h = percent_of(wininfo.h, args, .5);
+ wininfo.h = percent_of(wininfo.h, args, .99);
wininfo.y += orig - wininfo.h;
}

void cmd_cut_left(char *args) {
if (appstate & STATE_ACTIVE == 0)
return;
- wininfo.w = percent_of(wininfo.w, args, .5);
+ wininfo.w = percent_of(wininfo.w, args, .99);
}

void cmd_cut_right(char *args) {
int orig = wininfo.w;
if (appstate & STATE_ACTIVE == 0)
return;
- wininfo.w = percent_of(wininfo.w, args, .5);
+ wininfo.w = percent_of(wininfo.w, args, .99);
wininfo.x += orig - wininfo.w;
}

@@ -802,7 +802,7 @@ void update() {
XMapWindow(dpy, zone);
}

-void drawborderline(struct wininfo *info, Window win, GC gc,
XRectangle *rect) {
+void drawborderline(struct wininfo *info, Window win, GC gc,
XRectangle *rect, char id) {
int penoffset = ((info->border_thickness / 2) - (info->pen_size /
2));
XDrawLine(dpy, win, gc,
(rect->x + (rect->width / 2)),
@@ -816,6 +816,7 @@ void drawborderline(struct wininfo *info, Window
win, GC gc, XRectangle *rect) {
(rect->x + rect->width - penoffset),
(rect->y + (rect->height / 2))
);
+ XDrawString(dpy, win, gc, rect->x, rect->y+20, &id, 1);
}

void handle_keypress(XKeyEvent *e) {

Jordan Sissel

unread,
Dec 3, 2008, 3:58:04 AM12/3/08
to keynav...@googlegroups.com

Strung-together key sequences don't work in keynav. Not yet, anyway.


Attached is a throw-away patch at the above (because I suck at Xlib
programming).  It's just to give you an idea of the "zooming in" idea.
The labelling is not implemented, I just did a one-liner XDrawString
just to experiment with it, neither does the keybinding part.

What do you guys think?

 Sounds interesting. Comments on your patch inline.

Nazri.

throwaway patch follows..

diff --git a/keynav.c b/keynav.c
index cc37fe7..029e8f8 100644
--- a/keynav.c
+++ b/keynav.c
@@ -81,7 +81,7 @@ void cmd_start(char *args);
 void cmd_warp(char *args);

 void update();
-void drawborderline(struct wininfo *info, Window win, GC gc,
XRectangle *clip);
+void drawborderline(struct wininfo *info, Window win, GC gc,
XRectangle *clip, char id);
 void handle_keypress(XKeyEvent *e);
 void handle_commands(char *commands);
 void parse_config();
@@ -412,7 +412,7 @@ GC creategc(Window win) {

 void drawgrid(Window win, struct wininfo *info, int apply_clip) {
  GC gc;
-  XRectangle clip[30];
+  XRectangle clip[32];

I'll work on making this not a static array (or patches welcome). Making it a static XRectable *clip that grows if grid_x and grid_y combine to making more than the current size rectangles, etc.
 


  /* Default start with 4 cells, 2x2 */
-  wininfo.grid_x = 2;
-  wininfo.grid_y = 2;
+  wininfo.grid_x = 20;
+  wininfo.grid_y = 10;

You should be able to achieve this in your .keynavrc with "grid 20x10"

  wininfo.border_thickness = 5;
  wininfo.pen_size = 1;
@@ -586,28 +586,28 @@ void cmd_quit(char *args) {
 void cmd_cut_up(char *args) {
  if (appstate & STATE_ACTIVE == 0)
    return;
-  wininfo.h = percent_of(wininfo.h, args, .5);
+  wininfo.h = percent_of(wininfo.h, args, .99);

This can be achieved in .keynavrc with something like "move-left .99" instead of needing to patch the code.


+  XDrawString(dpy, win, gc, rect->x, rect->y+20, &id, 1);

Frame labelling sounds interesting, but I'm not sure it has a lot of applications. Do you prefer labeling the columns and rows only (like on a map, labels on the outside) or labelling every cell like B4 and C7 or both?

-Jordan


Nazri Ramliy

unread,
Dec 3, 2008, 4:54:44 AM12/3/08
to keynav...@googlegroups.com
On Wed, Dec 3, 2008 at 4:58 PM, Jordan Sissel <j...@semicomplete.com> wrote:
> Frame labelling sounds interesting, but I'm not sure it has a lot of
> applications. Do you prefer labeling the columns and rows only (like on a
> map, labels on the outside) or labelling every cell like B4 and C7 or both?

No, it's not like on a map. Each grid crossing would be labeled. The
purpose is to keep
our eyes fixated at or near the target area, then hit Ctrl+; which
brings up the grid, and
due to the sufficiently large number of cells, one or two of the
labels would be
conveniently close to our target that we don't have to move our eyes
at all to read it, and
while still focusing on the target, we move the grid crossing using
h/j/k/l (indirectly by
reducing the cell height and width) and once it's on the target we hit
the correct key
combo to activate clicking on the grid crossing associated with the label.

Thanks for pointing out the entries in the .keynavrc.

It's nice to hear from you so quick :) I've been poring over your old
blog posts on and
off for the last 2 hours or so (slow work day), scouring for gems
(found quite a few).

I found out your blog via your xdotool, which has been invaluable to
me (I paired it with wmctrl)
every single day at work for the last two months or so to automate the
mundane repetitive
things that I have todo. In other words, it save a lot of my time.
Thanks a lot for that!

nazri.

Yuri D'Elia

unread,
Dec 6, 2008, 9:15:46 AM12/6/08
to keynav...@googlegroups.com

On 3 Dec 2008, at 09:58, Jordan Sissel wrote:

>> Attached is a throw-away patch at the above (because I suck at Xlib
>> programming). It's just to give you an idea of the "zooming in"
>> idea.
>> The labelling is not implemented, I just did a one-liner XDrawString
>> just to experiment with it, neither does the keybinding part.
>>
>> What do you guys think?
>>
> Sounds interesting. Comments on your patch inline.

Interesting idea for me too.
I can't try the patch right now, so can someone put a screenshot online?

>> + XDrawString(dpy, win, gc, rect->x, rect->y+20, &id, 1);
>>
> Frame labelling sounds interesting, but I'm not sure it has a lot of
> applications. Do you prefer labeling the columns and rows only
> (like on a
> map, labels on the outside) or labelling every cell like B4 and C7
> or both?

I like the idea of frame labels for each cell.

For example, if we could use a 60x40 grid (lots of cells), and name
each cell with the minimal amount of fixed letters (like AA, AB, AC,
and so on), one could basically point and type(tm).

Chances are, that there are so many cells that if you can't exactly
point immediately, shifting the grid in one direction a time or two
will bring at least one cell into the target.

Just thinking...

Nazri Ramliy

unread,
Dec 6, 2008, 8:37:00 PM12/6/08
to keynav...@googlegroups.com
On Sat, Dec 6, 2008 at 10:15 PM, Yuri D'Elia <wav...@thregr.org> wrote:
> Interesting idea for me too.
> I can't try the patch right now, so can someone put a screenshot online?

You're not missing anything. What the patch did can be achieved by the
following in your keynavrc:

g grid 20x10
ctrl+l cut-right .99
ctrl+h cut-left .99
ctrl+k cut-up .99
ctrl+j cut-down .99

Hit 'g' after hitting ctrl+; and you'll see the 20x10 cells, then
ctrl+l/h/k/j shrinks each cell so that the chosen nearest
grid-crossing gets closer to your target.

My lame attempt at labeling the cells just draw the letters at the top
row and left column only.

The following are needed to make it happen:

1. "Strung together key sequences" support.
2. Labeling of each grid crossing
3. ???
4. Profit!!!

nazri

Jordan Sissel

unread,
Dec 7, 2008, 3:05:31 AM12/7/08
to keynav...@googlegroups.com

Mmmm profit.

These changes should be pretty easy to make. If someone wants to make a proper patch to implement these things before I get to it, I'm happy to accept. Otherwise, it's on my todo list. (I probably won't get to it until later this month or longer since I'm currently swamped with $job and sysadvent.blogspot.com)

If you don't hear from me on this in a month or so, feel free to ping this thread about it.

-Jordan



nazri



Nazri Ramliy

unread,
Dec 10, 2008, 12:46:00 PM12/10/08
to keynav...@googlegroups.com
On Sun, Dec 7, 2008 at 4:05 PM, Jordan Sissel <j...@semicomplete.com> wrote:
> These changes should be pretty easy to make. If someone wants to make a
> proper patch to implement these things before I get to it, I'm happy to
> accept.

Here's a patch. Comments are welcomed. (Now I think I suck less at Xlib :)

To make the cursor warp to a specific grid crossing, say b0, do the following:

1. hit Ctrl+; to activate keynav,
2. hit ,b0 (that's comma-bee-zero) in succession (the comma key starts
'recording' the next two keys that you press)
3. hit the spacebar and keynav should warp the cursor to wherever b0
is and perform a click there.

It'd work better with the following in your .keynavrc (because you'll
have more grid crossings, so there'll be less keypresses needed to go
to your target):

g grid 20x9


ctrl+l cut-right .99
ctrl+h cut-left .99
ctrl+k cut-up .99
ctrl+j cut-down .99

Hit g after hitting ctrl+;.

The grid size is 20 columns by 9 rows. 9 rows because if it were
higher than that then the labels that are greater than 9 would not fit
well inside the small red boxes.

The columns are labeled from 'a' onwards, while the rows are labeled
from '0' onwards. You can change the row labeling to start from 'a'
too, if you prefer (so that you can have more rows). This would make
labels like 'aa', 'ab', instead of 'a0', 'a1'.

Note that there is no checking for whether the number of columns or
grids goes beyond the printable letters.

Things that can be improved:

1. Once a grid-crossing has been selected, draw only that
grid-crossing in the next update - this would unclutter the display.
2. Use transparent color when drawing the label boxes (is it
possible?) - So that we can see what's behind it.
3. Use single pixel lines so that we can see more of where we want to
point the pointer to.
4. Push stuff down into keynavrc for further customization
(comma/label letters/etc)

Watch out for: memory leaks :D - I've implemented dynamic memory
allocation for the clipping and holes.
I don't have valgrind installed to test for any leak. My poor pipe is
congested with some torrents^H^H^H^H network activity that the
download of valgrind takes like forever. If anyone can test it for
any memory leak that'd be good.

nazri.

alternate.navigation.patch

Jordan Sissel

unread,
Dec 10, 2008, 1:35:38 PM12/10/08
to keynav...@googlegroups.com
On Wed, Dec 10, 2008 at 9:46 AM, Nazri Ramliy <ayie...@gmail.com> wrote:
On Sun, Dec 7, 2008 at 4:05 PM, Jordan Sissel <j...@semicomplete.com> wrote:
> These changes should be pretty easy to make. If someone wants to make a
> proper patch to implement these things before I get to it, I'm happy to
> accept.

Here's a patch. Comments are welcomed. (Now I think I suck less at Xlib :)

To make the cursor warp to a specific grid crossing, say b0, do the following:

1. hit Ctrl+; to activate keynav,
2. hit ,b0 (that's comma-bee-zero) in succession (the comma key starts
'recording' the next two keys that you press)
3. hit the spacebar and keynav should warp the cursor to wherever b0
is and perform a click there.

It'd work better with the following in your .keynavrc (because you'll
have more grid crossings, so there'll be less keypresses needed to go
to your target):

g grid 20x9
ctrl+l cut-right .99
ctrl+h cut-left .99
ctrl+k cut-up .99
ctrl+j cut-down .99

Hit g after hitting ctrl+;.

BTW, you can combine commands:

ctrl+; start, grid 20x9

If you want to do that in your .keynavrc (I have several that do this)

The columns are labeled from 'a' onwards, while the rows are labeled
from '0' onwards. You can change the row labeling to start from 'a'
too, if you prefer (so that you can have more rows). This would make
labels like 'aa', 'ab', instead of 'a0', 'a1'.

Note that there is no checking for whether the number of columns or
grids goes beyond the printable letters.

Things that can be improved:

1. Once a grid-crossing has been selected, draw only that
grid-crossing in the next update - this would unclutter the display.
2. Use transparent color when drawing the label boxes (is it
possible?) - So that we can see what's behind it.

This is possible if we use XCOMPOSITE somehow. I'll look into setting transparency, but transparency requires you run a compositing manager (like xcompmgr, or the beryl wm). Transparency is just a netwm setting (_NET_WM_WINDOW_OPACITY).


3. Use single pixel lines so that we can see more of where we want to
point the pointer to.
4. Push stuff down into keynavrc for further customization
(comma/label letters/etc)

Watch out for: memory leaks :D - I've implemented dynamic memory
allocation for the clipping and holes.
I don't have valgrind installed to test for any leak. My poor pipe is
congested with some torrents^H^H^H^H network activity that the
download of valgrind takes like forever.  If anyone can test it for
any memory leak that'd be good.

Hey, this is looks pretty good when I run it. Haven't looked much at the code, yet.

Nice work!

-Jordan


Nazri Ramliy

unread,
Dec 12, 2008, 9:31:43 AM12/12/08
to keynav...@googlegroups.com
On Thu, Dec 11, 2008 at 2:35 AM, Jordan Sissel <j...@semicomplete.com> wrote:
> ctrl+; start, grid 20x9
>
> If you want to do that in your .keynavrc (I have several that do this)

Thanks for the heads up. Heh I didn't notice that there's a sample
keynavrc bundled in the tarball.

There's a minor bug with the calculation of the cell locations - it
uses integer arithmetic which results in loss of precision. It's
visible when you do a few .99 cut-downs on a say 20x9 grid. You'll
notice that the bottom cell row is higher than the rest, and while
doing the cut downs the grid crossing near the bottom does not go down
all the time, it goes like down, up, down, up which is very annoying.

Attached patch fixes this issue. This patch is against keynav with my
alternate navigation patch.

nazri.

cell.location.fix.patch

Nazri Ramliy

unread,
Dec 18, 2008, 12:19:28 PM12/18/08
to keynav...@googlegroups.com
Another patch attached. hehe

This one gives me 50% improvement on the number of keypresses that I
have to make to warp to any pixel, i.e. it cuts down the number of
keypresses by half!

comma-[a-z]-[0-9] warps to the specified grid crossing (current
behavior), while apostrophe-[a-z]-[0-9] warps to the center of the
cell that owns the given bottom left grid crossing. Mnemonic: the
comma key is sort of at the bottom left of the apostrophe (at least on
my keyboard :)

After applying this I found that most of the time the area that I want
to click on fall right smack at a grid crossing or at the center of a
cell. If not, they're just a few .99 cuts-up/down/left/right away.

This patch is against keynav-20080614.01 with my
alternate.navigation.patch and cell.location.fix.patch patches.

nazri.

more.holes.patch
Reply all
Reply to author
Forward
0 new messages