joy2key
ジョイパッドの入力をキーボードのキーコードに変換するjoy2keyを試していたけど、window名の指定が面倒なのでフォーカスがあたったところ限定にしたオリジナル版を作ってみました。Shift, Control, Metaなどのmodifierがない簡易的なものです。
joy2keyのソースコードを見ればわかりますが、はっきりいっていまいちです。sleep(0.2)とか使い方間違ってるし。
はまっている方もいらっしゃるようです。
http://d.hatena.ne.jp/n9d/20080210/1202648836
$ ./myjoy2key -b "d c x s NoSymbol NoSymbol NoSymbol NoSymbol space Return a z" \ -a "Left Right Up Down"
#include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <errno.h> #include <unistd.h> #include <fcntl.h> #if !defined(MYJOY2KEY_DEBUG) #include <linux/joystick.h> #include <X11/Xlib.h> #include <X11/keysymdef.h> #else #include "myjoy2key_debug.h" #endif typedef struct { int pos_on; int neg_on; KeySym pos; KeySym neg; } Axis; typedef struct { char name[128]; int fd; int naxes; int nbuttons; Axis *axis; KeySym *button; } Joypad; typedef struct { Display *display; } Client; void usage(const char *); int joypad_load(Joypad *, const char *); int joypad_exec(Client *, Joypad *); int bind_axes(Joypad *, const char *); int bind_buttons(Joypad *, const char *); int gettok(const char *, char *, int, const char **); int sendkey(Client *, KeySym, int); void error(const char *, ...); int main(int argc, char **argv) { const char *progname; const char *devname; const char *axesstr; const char *buttonsstr; Joypad joypad; Client client; int opt; progname = argv[0]; devname = "/dev/input/js0"; axesstr = NULL; buttonsstr = NULL; while ((opt = getopt(argc, argv, "a:b:d:")) != -1) { switch (opt) { case 'a': axesstr = optarg; break; case 'b': buttonsstr = optarg; break; case 'd': devname = optarg; break; default: usage(progname); } } if ((client.display = XOpenDisplay(NULL)) == NULL) return EXIT_FAILURE; if (joypad_load(&joypad, devname) != 0) return EXIT_FAILURE; if (axesstr) if (bind_axes(&joypad, axesstr) != 0) return EXIT_FAILURE; if (buttonsstr) if (bind_buttons(&joypad, buttonsstr) != 0) return EXIT_FAILURE; while (joypad_exec(&client, &joypad) == 0) ; return EXIT_SUCCESS; } void usage(const char *progname) { printf("%s [-a axes] [-b buttons] [-d devname]\n", progname); exit(EXIT_FAILURE); } int joypad_load(Joypad *joy, const char *devname) { unsigned char v; size_t size; int i; if ((joy->fd = open(devname, O_RDONLY)) == -1) { error("open(`%s')", devname); return -1; } if (ioctl(joy->fd, JSIOCGNAME(sizeof(joy->name)), joy->name) < 0) { error("ioctl(name)"); close(joy->fd); return -1; } if (ioctl(joy->fd, JSIOCGAXES, &v) < 0) { error("ioctl(axes)"); close(joy->fd); return -1; } joy->naxes = v; if (ioctl(joy->fd, JSIOCGBUTTONS, &v) < 0) { error("ioctl(buttons)"); close(joy->fd); return -1; } joy->nbuttons = v; printf("NAME : %s\n", joy->name); printf("AXES : %d\n", joy->naxes); printf("BUTTONS : %d\n", joy->nbuttons); size = joy->naxes * sizeof(*joy->axis); if ((joy->axis = malloc(size)) == NULL) { error("malloc(axis: %zu)", size); close(joy->fd); return -1; } for (i = 0; i < joy->naxes; i++) { joy->axis[i].pos = NoSymbol; joy->axis[i].neg = NoSymbol; joy->axis[i].pos_on = 0; joy->axis[i].neg_on = 0; } size = joy->nbuttons * sizeof(*joy->button); if ((joy->button = malloc(size)) == NULL) { error("malloc(button: %zu)", size); close(joy->fd); free(joy->axis); return -1; } for (i = 0; i < joy->nbuttons; i++) joy->button[i] = NoSymbol; return 0; } int bind_axes(Joypad *joy, const char *s) { char token[80]; const char *brkp; int n; brkp = NULL; for (n = 0; gettok(s, token, sizeof(token), &brkp); n++) { if (n >= joy->naxes * 2) { error("Too many AXES %d > %d * 2.\n", n + 1, joy->naxes); return -1; } if (n & 1) joy->axis[n / 2].pos = XStringToKeysym(token); else joy->axis[n / 2].neg = XStringToKeysym(token); } if (n < joy->naxes * 2) { error("Too few AXES %d < %d * 2.\n", n, joy->naxes); return -1; } return 0; } int bind_buttons(Joypad *joy, const char *s) { char token[80]; const char *brkp; int n; brkp = NULL; for (n = 0; gettok(s, token, sizeof(token), &brkp); n++) { if (n >= joy->nbuttons) { error("Too many BUTTONS %d > %d.\n", n + 1, joy->nbuttons); return -1; } joy->button[n] = XStringToKeysym(token); } if (n < joy->nbuttons) { error("Too few BUTTONS %d < %d.\n", n, joy->nbuttons); return -1; } return 0; } int gettok(const char *s, char *buf, int len, const char **brkp) { const char *p; if (*brkp == NULL) p = s; else p = *brkp; if (*p == '\0') return 0; while (*p == ' ') p++; do { if (len <= 1) { error("Internal buffer too small.\n"); return 0; } *buf++ = *p++; len--; } while (*p != ' ' && *p != '\0'); *buf = '\0'; *brkp = p; return 1; } int joypad_exec(Client *client, Joypad *joy) { struct js_event e; KeySym key; Axis *axis; if (read(joy->fd, &e, sizeof(e)) != sizeof(e)) return -1; switch (e.type & ~JS_EVENT_INIT) { case JS_EVENT_BUTTON: if ((key = joy->button[e.number]) != NoSymbol) sendkey(client, key, e.value ? KeyPress : KeyRelease); break; case JS_EVENT_AXIS: axis = &joy->axis[e.number]; if (axis->neg_on && e.value >= 0) { sendkey(client, axis->neg, KeyRelease); axis->neg_on = 0; } if (axis->pos_on && e.value <= 0) { sendkey(client, axis->pos, KeyRelease); axis->pos_on = 0; } if (axis->neg != NoSymbol && e.value < 0) { sendkey(client, axis->neg, KeyPress); axis->neg_on = 1; } if (axis->pos != NoSymbol && e.value > 0) { sendkey(client, axis->pos, KeyPress); axis->pos_on = 1; } break; default: break; } return 0; } int sendkey(Client *client, KeySym key, int type) { Display *display = client->display; XKeyEvent event; Window window; int r; XGetInputFocus(display, &window, &r); event.type = type; event.serial = 0; /* undef */ event.send_event = 0; /* undef */ event.display = display; event.window = window; event.root = DefaultRootWindow(display); event.subwindow = None; event.time = CurrentTime; event.x = 1; /* undef */ event.y = 1; /* undef */ event.x_root = 1; /* undef */ event.y_root = 1; /* undef */ event.state = 0; event.keycode = XKeysymToKeycode(display, key); event.same_screen = True; /* undef */ XSendEvent(display, window, True, KeyPressMask, (XEvent *)&event); XFlush(display); return 0; } void error(const char *fmt, ...) { int sverror; va_list ap; sverror = errno; fprintf(stderr, "Error: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if (strchr(fmt, '\n') == NULL) fprintf(stderr, " %s\n", strerror(sverror)); errno = sverror; }
BCPLにもコルーチンがあったんだ
ますますBCPLに興味が沸いてきたかも。
Proactor Pattern
http://www.artima.com/articles/io_design_patterns.html
私がやろうとしているのは、まさにこのProactor Emulationと呼ばれるものです。そして今悩んでいるのは、Proactor jobのスケジューリング。
hgwebでリビジョングラフを表示
1.0.2の最新のリリース版には入っていませんが、trunk(?)というかmainでは、hgwebでリビジョングラフの表示ができるようです。
このサンプルでは、paperというstyleを使っています。gitwebに比べてシンプルでMercurialらしいですね。結構好みです。
The Game of Life
http://d.hatena.ne.jp/giveup/20080505
もう少し練ってみた。
#include <stdio.h> #include <string.h> #include <stdbool.h> #include <unistd.h> #define MAX(a,b) ((a)>(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b)) void l(_Bool mas[2][10][10],int o,int n) { for(int x=0;x<10;x++) for(int c,y=0;c=0,y<10;mas[n][x][y]=c==3||(c==4&&mas[o][x][y]),y++) for(int xx=MAX(x-1,0);xx<=MIN(x+1,9);xx++) for(int yy=MAX(y-1,0);yy<=MIN(y+1,9);yy++) c+=mas[o][xx][yy]; } void p(_Bool (*o)[10],int step) { printf("\x1b\x5b\x32\x4a\x1b\x5b\x48%d step\n",step); for(int x=0;x<10;x++,putchar('\n')) for(int y=0;y<10;y++) putchar("-O"[o[x][y]]); } int main(void) { _Bool mas[2][10][10] = { { {0,1,0,0,1,0,0,1,0,0}, {0,0,1,0,0,0,1,1,0,0}, {0,1,1,1,0,0,0,1,1,0}, {0,1,0,0,0,1,1,0,1,0}, {0,0,0,1,1,0,0,0,0,0}, {0,1,1,1,0,0,0,0,1,1}, {0,0,1,0,1,0,0,1,0,0}, {1,1,1,0,0,0,1,0,1,0}, {0,0,0,0,1,0,0,0,0,1}, {0,0,1,1,1,0,0,1,0,0}, }, }; for(int i=0,o=0,n=1;i<100&&memcmp(mas[0],mas[1],100*sizeof(_Bool));i++,n^=o^=n^=o) { l(mas,o,n); p(mas[o],i); usleep(100000); } return 0; }
『ビューティフルコード』
ビューティフルコード (THEORY/IN/PRACTICE)
- 作者: Brian Kernighan,Jon Bentley,まつもとゆきひろ,Andy Oram,Greg Wilson,久野禎子,久野靖
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/04/23
- メディア: 大型本
- 購入: 30人 クリック: 617回
- この商品を含むブログ (190件) を見る
- 4/18 Amazonからおすすめのメールがくる。
- 4/20 注文する。
- 4/25 Amazonから在庫がないというメールがくる。
- 4/29 Amazonの注文をキャンセルする。
- 4/29 紀伊国屋で注文する。
- 5/2 届く。
今年のゴールデンウィークはこれで退屈せずに済む。
29章の『エッセイのごときプログラム』はなかなか興味深い。特にRakefileの文法の話の中で、文法を既存のRubyにあわせる『シンプルさ』を追求するよりも、『人間の書くプログラムのシンプルさ』を選んだとあった。
(a)
task({:default => [:test]}) task(:test, lambda(){ ruby "test/unittest.rb" })
こう書くよりも
(b)
task :default => [:test] task :test do ruby "test/unittest.rb" end
こう書く方がより人間が書くコードとしてはシンプルになるということだ。
(b)の方がシンプルであるというより、(b)の方が『自然な表現』であると思った。
本の中でrakeのRakefileをDSL(Domain Specific Language)と言っていたが、DSLというのは、特定の目的のために最適化された言語という意味で、これはその目的にあった表現の『自然さ』の追求なのではないかと思う。