3 let (~
>) = Bytes.unsafe_of_string
22 type wid
= int and screenno
= int and vid
= int and atom
= int
24 external glxinit
: string -> wid
-> screenno
-> vid
= "ml_glxinit"
25 external glxcompleteinit
: unit -> unit = "ml_glxcompleteinit"
26 external swapb
: unit -> unit = "ml_swapb"
27 external setcursor
: cursor
-> unit = "ml_setcursor"
32 | Fs
of (int * int * int * int)
35 let mink = ref max_int
36 let maxk = ref min_int
38 let fifo = ref (Queue.create
())
40 let protoatom = ref ~
-1
41 let deleatom = ref ~
-1
42 let nwmsatom = ref ~
-1
43 let maxvatom = ref ~
-1
44 let maxhatom = ref ~
-1
45 let fulsatom = ref ~
-1
49 let fullscreen = ref (fun _
-> ())
50 let setwmname = ref (fun _
-> ())
51 let actwin = ref (fun _
-> ())
52 let sock = ref Unix.stdin
58 let stringatom = ref 31
59 let curcurs = ref CURSOR_TEXT
68 method map
(_
:bool) = ()
70 method visible
(_
:visiblestate
) = ()
71 method reshape
(_
:int) (_
:int) = ()
72 method mouse
(_
:int) (_
:bool) (_
:int) (_
:int) (_
:int) = ()
73 method motion
(_
:int) (_
:int) = ()
74 method pmotion
(_
:int) (_
:int) = ()
75 method key
(_
:int) (_
:int) = ()
76 method enter
(_
:int) (_
:int) = ()
78 method winstate
(_
:winstate list
) = ()
79 method quit
: 'a
. 'a
= exit
0
80 method scroll
(_
:int) (_
:int) = ()
81 method zoom
(_
:float) (_
:int) (_
:int) = ()
82 method opendoc
(_
:string) = ()
86 let settitle s
= !S.setwmname (~
> s
)
87 let fullscreen () = !S.fullscreen !S.wid
88 let fontsizescale n
= float n
*. !S.fscale |> truncate
96 let withalt mask
= mask
land altmask != 0
97 let withctrl mask
= mask
land ctrlmask != 0
98 let withshift mask
= mask
land shiftmask != 0
99 let withmeta mask
= mask
land metamask != 0
100 let withnone mask
= mask
land (altmask + ctrlmask + shiftmask + metamask) = 0
102 let makereq opcode len reqlen
=
103 let s = Bytes.create len
in
109 let s = Bytes.create n
in
111 let m = tempfailureretry
(Unix.read
sock s pos
) n
in
116 ignore
(tempfailureretry
(Unix.select
[sock] [] []) 0.01);
117 loop (pos
+ m) (n
- m)
123 let sendstr1 s pos len
sock =
124 let s = Bytes.unsafe_to_string
s in
125 vlog
"%d <= %S" !S.seq s;
127 let n = tempfailureretry
(Unix.write_substring
sock s pos
) len
in
129 then error
"send %d returned %d" len
n
131 let updkmap sock resp
=
132 let syms = r8 resp
1 in
133 let len = r32 resp
4 in
136 then readstr sock (4*len)
139 let m = len / syms in
140 S.keymap := Array.make_matrix
!S.maxk syms 0xffffff;
148 let v = r32
data k in
149 !S.keymap.(i
).(l
) <- v;
157 let updmodmap sock resp
=
159 let len = r16 resp
4 in
162 then readstr sock (len*4)
167 let modmap = Array.make_matrix
8 n 0xffffff in
176 let code = r8
data p in
177 modmap.(l
).(m) <- code;
180 let ki = code - !S.mink in
183 let a = !S.keymap.(ki) in
185 if not
(i
= Array.length
a || i
> 3)
189 then S.capslmask := 2
197 let ki = code - !S.mink in
200 let a = !S.keymap.(ki) in
202 if not
(i
= Array.length
a || i
> 3)
206 | 0xfe03 -> S.levl3mask := 1 lsl l
207 | 0xfe11 -> S.levl5mask := 1 lsl l
208 | 0xff7f -> S.numlmask := 1 lsl l
220 let sendwithrep sock s f
=
221 Queue.push f
!S.fifo;
222 sendstr1 s 0 (Bytes.length
s) sock
225 let l1 = Bytes.length b1
and l2
= Bytes.length b2
in
226 let l = (l1 + l2
) land 3 in
227 let pl = if l > 0 then 4 - l else 0 in
228 let b = Bytes.create
(l1 + l2
+ pl) in
229 Bytes.blit b1
0 b 0 l1;
230 Bytes.blit b2
0 b l1 l2
;
233 let internreq name onlyifexists
=
234 let s = makereq 16 8 8 in
235 let s = padcat s name
in
236 w8
s 1 (if onlyifexists
then 1 else 0);
237 w16
s 2 (Bytes.length
s / 4);
238 w16
s 4 (Bytes.length name
);
241 let sendintern sock s onlyifexists f
=
242 let s = internreq s onlyifexists
in
245 let createwindowreq wid parent
x y w h bw eventmask vid depth mid
=
246 let s = makereq 1 44 11 in
255 w16
s 22 0; (* copyfromparent *)
256 w32
s 24 vid
; (* visual *)
257 w32
s 28 0x2808; (* valuemask =
261 w32
s 32 0; (* border pixel*)
266 let createcolormapreq mid
wid vid
=
267 let s = makereq 78 16 4 in
274 let getgeometryreq wid =
275 let s = makereq 14 8 2 in
280 let s = makereq 8 8 2 in
284 let getkeymapreq first count
=
285 let s = makereq 101 8 2 in
290 let changepropreq wid prop typ format props
=
291 let s = makereq 18 24 0 in
292 let s = padcat s props
in
294 w16
s 2 (Bytes.length
s / 4);
299 let ful = Bytes.length props
/ (match format
with
303 | n -> error
"no idea what %d means" n)
308 let getpropreq delete
wid prop typ
=
309 let s = makereq 20 24 6 in
310 w8
s 1 (if delete
then 1 else 0);
318 let configurewindowreq wid mask values
=
319 let s = makereq 12 12 0 in
320 let s = padcat s values
in
321 w16
s 2 (Bytes.length
s / 4);
327 let s = Bytes.create
4 in
331 let clientmessage format
seq wid typ
data =
332 let s = makereq 33 12 0 in
333 let s = padcat s data in
340 let sendeventreq propagate destwid mask
data =
341 let s = makereq 25 12 11 in
342 let s = padcat s data in
349 let getmodifiermappingreq () =
352 let queryextensionreq name
=
353 let s = makereq 98 8 0 in
354 let s = padcat s name
in
355 w16
s 2 (Bytes.length
s / 4);
356 w16
s 4 (Bytes.length name
);
359 let getkeysym pkpk
code mask
=
360 if (pkpk
>= 0xff80 && pkpk
<= 0xffbd)
361 || (pkpk
>= 0x11000000 && pkpk
<= 0x1100ffff)
363 if mask
land !S.numlmask != 0
365 let keysym = !S.keymap.(code - !S.mink).(1) in
366 if keysym = 0 then pkpk
else keysym
371 if pkpk
land 0xf000 = 0xf000
373 else (mask
land 1) lxor ((mask
land !S.capslmask) lsr 1)
376 if !S.xkb && mask
land 0x2000 != 0
379 let l3 = (mask
land !S.levl3mask) != 0 in
380 let l4 = (mask
land !S.levl5mask) != 0 in
382 if l3 then (if l4 then 8 else 4) else (if l4 then 6 else 0)
384 let keysym = !S.keymap.(code - !S.mink).(index) in
385 if index land 1 = 1 && keysym = 0
386 then !S.keymap.(code - !S.mink).(index - 1)
390 let getkeysym code mask
=
391 let pkpk = !S.keymap.(code - !S.mink).(0) in
392 if !S.xkb && pkpk lsr 8 = 0xfe (* XKB *)
394 else getkeysym pkpk code mask
397 let resp = readstr sock 32 in
398 let opcode = r8
resp 0 in
399 match opcode land lnot
0x80 with
404 and resid
= r32
resp 4
407 error
"code=%d serial=%d resid=%#x min=%d maj=%d\n%S"
408 code serial resid min maj
(Bytes.unsafe_to_string
resp);
410 | 1 -> (* response *)
411 let rep = Queue.pop
!S.fifo in
414 | 2 -> (* key press *)
415 if Array.length
!S.keymap > 0
417 let code = r8
resp 1 in
418 let mask = r16
resp 28 in
419 let keysym = getkeysym code mask in
420 vlog
"keysym = %x %c mask %#x code %d"
421 keysym (Char.unsafe_chr
keysym) mask code;
423 then !S.t#key
keysym mask;
425 | 3 -> (* key release *)
426 if Array.length
!S.keymap > 0
428 let code = r8
resp 1 in
429 let mask = r16
resp 28 in
430 let keysym = getkeysym code mask in
431 vlog
"release keysym = %x %c mask %#x code %d"
432 keysym (Char.unsafe_chr
keysym) mask code;
434 | 4 -> (* buttonpress *)
438 and m = r16
resp 28 in
439 !S.t#mouse
n true x y m;
442 | 5 -> (* buttonrelease *)
446 and m = r16
resp 28 in
447 !S.t#mouse
n false x y m;
448 vlog
"release %d %d %d" n x y;
451 let x = r16s
resp 24 in
452 let y = r16s
resp 26 in
453 let m = r16
resp 28 in
455 then !S.t#pmotion
x y
456 else !S.t#motion
x y;
457 vlog
"move %dx%d => %d" x y m;
461 and y = r16s
resp 26 in
463 vlog
"enter %d %d" x y;
476 | 12 -> (* exposure *)
480 | 15 -> (* visibility *)
485 | 1 -> PartiallyObscured
488 dolog
"unknown visibility %d" v;
492 vlog
"visibility %d" v;
494 | 11 -> (* keymapnotify *)
496 let s = getkeymapreq !S.mink (!S.maxk - !S.mink-1) in
497 sendwithrep sock s (updkmap sock);
502 let s = getmodifiermappingreq () in
503 sendwithrep sock s (updmodmap sock);
505 | 33 -> (* clientmessage *)
506 let atom = r32
resp 8 in
507 if atom = !S.protoatom
509 let atom = r32
resp 12 in
510 if atom = !S.deleatom
512 vlog
"atom %#x" atom;
514 | 21 -> (* reparent *)
517 | 22 -> (* configure *)
521 and h = r16
resp 22 in
522 vlog
"configure cur [%d %d %d %d] conf [%d %d %d %d]"
525 if w != !S.w || h != !S.h
526 then !S.t#reshape
w h;
532 | 24 -> (* Gravity notify *)
535 | 28 -> (* Property notify *)
536 let atom = r32
resp 8 in
537 if atom = !S.nwmsatom
539 let s = getpropreq false !S.wid atom 4 in
540 sendwithrep sock s (fun resp ->
542 let len = r32
resp 4 in
543 let nitems = r32
resp 16 in
548 let s = readstr sock (len*4) in
553 let atom = r32
s (i
*4) in
555 if atom = !S.maxhatom
558 if atom = !S.maxvatom
561 if atom = !S.fulsatom
563 S.fs := S.Fs
(!S.x, !S.y, !S.w, !S.h);
573 !S.t#winstate
(List.sort compare
wsl)
576 | n -> dolog
"event %d %S" n (Bytes.unsafe_to_string
resp)
581 if hasdata
sock then loop ();
585 let sendstr s ?
(pos
=0) ?
(len=Bytes.length
s) sock =
586 sendstr1 s pos
len sock;
587 if hasdata
sock then readresp sock
592 let s = Bytes.create
8 in
595 let s = configurewindowreq !S.wid 0x000c s in
597 else !S.fullscreen !S.wid
602 let syncsendwithrep sock secstowait
s f
=
603 let completed = ref false in
604 sendwithrep sock s (fun resp -> f
resp; completed := true);
605 let now = Unix.gettimeofday
in
606 let deadline = now () +. secstowait
in
607 let rec readtillcompletion () =
609 let timeout = deadline -. now () in
612 else Unix.select
[sock] [] [] timeout
614 let r, _
, _
= tempfailureretry
sf deadline in
616 | [] -> error
"didn't get X response in %f seconds, aborting" secstowait
620 then readtillcompletion ();
622 readtillcompletion ()
625 let s = mapreq !S.wid in
628 let syncsendintern sock secstowait
s onlyifexists f
=
629 let s = internreq s onlyifexists
in
630 syncsendwithrep sock secstowait
s f
632 let setup disp
sock rootwid screennum
w h =
633 let s = readstr sock 2 in
634 let n = Bytes.length
s in
636 then error
"failed to read X connection setup response n=%d" n;
637 match Bytes.get
s 0 with
639 let reasonlen = r8
s 1 in
640 let s = readstr sock 6 in
645 let data = readstr sock len in
646 let reason = Bytes.sub
data 0 reasonlen in
647 error
"X connection failed maj=%d min=%d reason=%S"
648 maj min
(Bytes.unsafe_to_string
reason);
650 | '
\002'
-> error
"X connection setup failed: authentication required";
653 let s = readstr sock 38 in
657 and idbase = r32
s 10
658 and idmask
= r32
s 14
660 and screens
= r8
s 26
661 and formats
= r8
s 27
663 and maxkk
= r8
s 33 in
664 let data = readstr sock (4*add
-32) in
665 let vendor = Bytes.sub
data 0 vlen
in
666 let pos = ((vlen
+3) land lnot
3) + formats
*8 in
668 if screennum
>= screens
669 then error
"invalid screen %d, max %d" screennum
(screens
-1);
672 let rec findscreen n pos =
677 let ndepths = r8
data (pos+39) in
678 let rec skipdepths n pos =
683 let nvisiuals = r16
data (pos+2) in
684 pos + nvisiuals*24 + 8
688 skipdepths n (pos+40)
694 let root = if rootwid
= 0 then r32
data pos else rootwid
in
695 let rootw = r16
data (pos+20)
696 and rooth
= r16
data (pos+22)
697 and rootdepth
= r8
data (pos+38)in
699 S.fscale := float rooth
/. 1440.0;
703 vlog
"vendor = %S, maj=%d min=%d" (Bytes.unsafe_to_string
vendor) maj min
;
704 vlog
"screens = %d formats = %d" screens formats
;
705 vlog
"minkk = %d maxkk = %d" minkk maxkk
;
706 vlog
"idbase = %#x idmask = %#x" idbase idmask
;
707 vlog
"root=%#x %dx%d" root rootw rooth
;
708 vlog
"wmm = %d, hmm = %d" (r16
data (pos+24)) (r16
data (pos+26));
709 vlog
"visualid = %#x" (r32
data (pos+32));
710 vlog
"root depth = %d" rootdepth
;
712 let wid = !S.idbase in
719 let vid = glxinit disp
wid screennum
in
720 let ndepths = r8
data (pos+39) in
721 let rec finddepth n'
pos =
723 then error
"cannot find depth for visual %#x" vid;
724 let depth = r8
data pos in
725 let nvisuals = r16
data (pos+2) in
726 let rec findvisual n pos =
728 then finddepth (n'
+1) pos
730 let id = r32
data pos in
733 else findvisual (n+1) (pos+24)
737 let depth = finddepth 0 (pos+40) in
739 let s = createcolormapreq mid root vid in
743 + 0x00000001 (* KeyPress *)
744 (* + 0x00000002 *) (* KeyRelease *)
745 + 0x00000004 (* ButtonPress *)
746 + 0x00000008 (* ButtonRelease *)
747 + 0x00000010 (* EnterWindow *)
748 + 0x00000020 (* LeaveWindow *)
749 + 0x00000040 (* PointerMotion *)
750 (* + 0x00000080 *) (* PointerMotionHint *)
751 (* + 0x00000100 *) (* Button1Motion *)
752 (* + 0x00000200 *) (* Button2Motion *)
753 (* + 0x00000400 *) (* Button3Motion *)
754 (* + 0x00000800 *) (* Button4Motion *)
755 (* + 0x00001000 *) (* Button5Motion *)
756 + 0x00002000 (* ButtonMotion *)
757 + 0x00004000 (* KeymapState *)
758 + 0x00008000 (* Exposure *)
759 + 0x00010000 (* VisibilityChange *)
760 + 0x00020000 (* StructureNotify *)
761 (* + 0x00040000 *) (* ResizeRedirect *)
762 (* + 0x00080000 *) (* SubstructureNotify *)
763 (* + 0x00100000 *) (* SubstructureRedirect *)
764 (* + 0x00200000 *) (* FocusChange *)
765 + 0x00400000 (* PropertyChange *)
766 (* + 0x00800000 *) (* ColormapChange *)
767 (* + 0x01000000 *) (* OwnerGrabButton *)
770 let s = createwindowreq wid root 0 0 w h 0 mask vid depth mid in
774 sock (~
> "WM_PROTOCOLS") false (fun resp ->
775 S.protoatom := r32
resp 8;
777 sock (~
> "WM_DELETE_WINDOW") false (fun resp ->
778 S.deleatom := r32
resp 8;
779 let s = s32 !S.deleatom in
780 let s = changepropreq wid !S.protoatom 4 32 s in
786 sock (~
> "WM_CLIENT_MACHINE") false (fun resp ->
787 let atom = r32
resp 8 in
790 try Unix.gethostname
()
792 dolog
"error getting host name: %s" @@ exntos exn
;
797 let s = changepropreq wid atom !S.stringatom 8
801 sock (~
> "_NET_WM_PID") false (fun resp ->
802 let atom = r32
resp 8 in
803 let pid = Unix.getpid
() in
805 let s = changepropreq wid atom 6(*cardinal*) 32 s in
810 S.actwin := (fun () ->
811 let s = Bytes.create
4 in
812 let s = configurewindowreq wid 0x40 s in
814 let s = mapreq wid in
819 sock (~
> "_NET_ACTIVE_WINDOW") true (fun resp ->
820 let atom = r32
resp 8 in
821 S.actwin := (fun () ->
822 let data = Bytes.make
20 '
\000'
in
823 let cm = clientmessage 32 0 wid atom data in
824 let s = sendeventreq 0 root 0x180000 cm in
830 sock 2.0 (~
> "WM_CLASS") false (fun resp ->
831 let atom = r32
resp 8 in
832 let llpp = ~
> "llpp\000llpp\000" in
833 let s = changepropreq wid atom 31 8 llpp in
837 let s = getkeymapreq !S.mink (!S.maxk - !S.mink) in
838 sendwithrep sock s (updkmap sock);
840 let s = getmodifiermappingreq () in
841 sendwithrep sock s (updmodmap sock);
844 sock (~
> "UTF8_STRING") true (fun resp ->
845 let atom = r32
resp 8 in
847 then S.stringatom := atom;
851 let s = changepropreq wid 39 !S.stringatom 8 s in
854 S.setwmname := setwmname;
856 sock (~
> "_NET_WM_NAME") true (fun resp ->
857 let atom = r32
resp 8 in
859 then S.setwmname := (fun s ->
861 let s = changepropreq wid atom !S.stringatom 8 s in
867 sock (~
> "_NET_WM_STATE") true (fun resp ->
868 S.nwmsatom := r32
resp 8;
871 sendintern sock (~
> "_NET_WM_STATE_MAXIMIZED_VERT") true (fun resp ->
872 S.maxvatom := r32
resp 8;
874 sendintern sock (~
> "_NET_WM_STATE_MAXIMIZED_HORZ") true (fun resp ->
875 S.maxhatom := r32
resp 8;
878 sock (~
> "_NET_WM_STATE_FULLSCREEN") false (fun resp ->
879 S.fulsatom := r32
resp 8;
884 let data = Bytes.make
20 '
\000'
in
887 | S.NoFs
-> S.Fs
(-1, -1, -1, -1), 1
888 | S.Fs _
-> S.NoFs
, 0
891 w32
data 4 !S.fulsatom;
893 let cm = clientmessage 32 0 wid !S.nwmsatom data in
894 let s = sendeventreq 0 root 0x180000 cm in
901 let s = queryextensionreq (~
> "XKEYBOARD") in
904 let present = r8
resp 8 in
907 let maj = r8
resp 9 in
908 let s = Bytes.create
8 in
909 w8
s 0 maj; (* XKB *)
910 w8
s 1 0; (* XKBUseExtension *)
911 w16
s 2 2; (* request-length *)
912 w16
s 4 1; (* wantedMajor *)
913 w16
s 6 0; (* watnedMinor *)
917 let supported = r8
resp 1 in
918 S.xkb := supported != 0
922 let s = getgeometryreq wid in
923 syncsendwithrep sock 2.0 s (fun resp ->
926 and h = r16
resp 18 in
931 | c
-> error
"unknown connection setup response %d" (Char.code c
)
933 let getauth haddr dnum
=
935 if emptystr
haddr || haddr = "localhost"
937 try Unix.gethostname
()
939 dolog
"failed to resolve `%S': %s" haddr @@ exntos exn
;
944 try Sys.getenv
"XAUTHORITY", true
946 try Filename.concat
(Sys.getenv
"HOME") ".Xauthority", false
947 with Not_found
-> E.s, false
951 let rb pos = Char.code (Bytes.get
s pos) in
952 (rb 1) lor ((rb 0) lsl 8)
956 let s = really_input_string ic
2 in
957 let n = r16be (~
> s) in
958 really_input_string ic
n
960 let family = really_input_string ic
2 in
964 match int_of_string
nums with
969 dolog
"display number(%S) is not an integer (corrupt %S?): %s"
970 nums path @@ exntos exn
977 vlog
"family %S addr %S(%S) num %S(%d) name %S data %S"
978 family addr haddr nums dnum
name data;
980 | Some num
when addr = haddr && num
= dnum
->
987 | End_of_file
-> E.s, E.s
989 dolog
"exception while reading X authority data (%S): %s"
999 match open_in_bin
path with
1004 dolog
"failed to open X authority file `%S' : %s" path @@ exntos exn
1010 try Sys.getenv
"DISPLAY"
1012 error
"cannot get DISPLAY evironment variable: %s" @@ exntos exn
1016 then error
"invalid DISPLAY(%s) %S" w d
1018 let s = String.sub
d b (e
- b) in
1021 error
"invalid DISPLAY %S can not parse %s(%S): %s" d w s @@ exntos exn
1024 if pos = String.length
d
1025 then error
"invalid DISPLAY %S no display number specified" d
1029 let rec pdispnum pos1
=
1030 if pos1
= String.length
d
1031 then getnum "display number" (pos+1) pos1
, 0
1035 let dispnum = getnum "display number" (pos+1) pos1
in
1036 let rec pscreennum pos2
=
1037 if pos2
= String.length
d
1038 then getnum "screen number" (pos1
+1) pos2
1041 | '
0'
.. '
9'
-> pscreennum (pos2
+1)
1043 error
"invalid DISPLAY %S, cannot parse screen number" d
1045 dispnum, pscreennum (pos1
+1)
1046 | '
0'
.. '
9'
-> pdispnum (pos1
+1)
1047 | _
-> error
"invalid DISPLAY %S, cannot parse display number" d
1049 String.sub
d 0 pos, pdispnum (pos+1)
1053 let host, (dispnum, screennum
) = phost 0 in
1054 let aname, adata
= getauth host dispnum in
1057 if emptystr
host || host.[0] = '
/'
|| host = "unix"
1059 (Unix.socket
Unix.PF_UNIX
Unix.SOCK_STREAM
0,
1060 Unix.ADDR_UNIX
("\000/tmp/.X11-unix/X" ^ string_of_int
dispnum))
1063 try Unix.gethostbyname
host
1064 with exn
-> error
"cannot resolve %S: %s" host @@ exntos exn
1066 let addr = h.Unix.h_addr_list
.(0) in
1067 let port = 6000 + dispnum in
1068 let fd = Unix.socket
Unix.PF_INET
Unix.SOCK_STREAM
0 in
1069 fd, (Unix.ADDR_INET
(addr, port))
1071 try Unix.connect
fd addr; fd
1072 with exn
-> error
"failed to connect to X: %s" @@ exntos exn
1074 Unix.set_close_on_exec
fd;
1075 let s = Bytes.create
12 in
1076 let s = padcat s (~
> aname) in
1077 let s = padcat s (~
> adata
) in
1078 Bytes.set
s 0 ordermagic;
1081 w16
s 6 (String.length
aname);
1082 w16
s 8 (String.length adata
);
1083 sendstr1 s 0 (Bytes.length
s) fd;
1085 setup d fd 0 screennum
w h;
1089 let setcursor cursor
=
1090 if cursor
!= !S.curcurs
1093 S.curcurs := cursor
;
1097 let t = Hashtbl.create
20
1098 and f
= Hashtbl.create
20 in
1100 List.iter
(fun s -> Hashtbl.add t s k) (n::nl
);
1104 let s = String.make
1 c
in
1105 add s [] (Char.code c
)
1108 let an = Char.code a and bn
= Char.code b in
1109 for i
= an to bn
do addc (Char.chr i
) done;
1114 String.iter
addc "`~!@#$%^&*()-_=+\\|[{]};:,./<>?";
1115 for i
= 0 to 29 do add ("f" ^ string_of_int
(i
+1)) [] (0xffbe + i
) done;
1116 add "space" [] 0x20;
1117 add "ret" ["return"; "enter"] 0xff0d;
1118 add "tab" [] 0xff09;
1119 add "left" [] 0xff51;
1120 add "right" [] 0xff53;
1121 add "home" [] 0xff50;
1122 add "end" [] 0xff57;
1123 add "ins" ["insert"] 0xff63;
1124 add "del" ["delete"] 0xffff;
1125 add "esc" ["escape"] 0xff1b;
1126 add "pgup" ["pageup"] 0xff55;
1127 add "pgdown" ["pagedown"] 0xff56;
1128 add "backspace" [] 0xff08;
1130 add "down" [] 0xff54;
1131 add "menu" [] 0xff67;
1135 try Hashtbl.find xlatf
k
1136 with Not_found
-> Printf.sprintf
"%#x" k
1139 try Hashtbl.find xlatt name
1141 if String.length
name = 1
1142 then Char.code name.[0]
1143 else int_of_string
name
1148 | 0xff08 -> Backspace
1170 | 0xffab -> Ascii '
+'
1171 | 0xffad -> Ascii '
-'
1173 | code when code > 31 && code < 128 -> Ascii
(Char.unsafe_chr
code)
1174 | code when code >= 0xffb0 && code <= 0xffb9 ->
1175 Ascii
(Char.unsafe_chr
(code - 0xffb0 + 0x30))
1176 | code when code >= 0xffbe && code <= 0xffc8 -> Fn
(code - 0xffbe + 1)
1177 | code when code land 0xff00 = 0xff00 -> Ctrl
code
1180 let cAp = "https://github.com/astrand/xclip"