Unix.KbdMouse.Mod 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. (* ETH Oberon, Copyright 2000 ETH Zürich Institut für Computersysteme, ETH Zentrum, CH-8092 Zürich.
  2. Refer to the general ETH Oberon System license contract available at: http://www.oberon.ethz.ch/ *)
  3. MODULE KbdMouse; (* g.f. 9.7.07 *)
  4. (* replacement for the keyboard and mouse drivers in the Unix ports *)
  5. IMPORT Machine, S := SYSTEM, Inputs, Plugins, X11, Displays, XDisplay, Api:=X11Api, Modules, Objects;
  6. CONST
  7. ML = 0; MM = 1; MR = 2;
  8. ModeSwitch = 13;
  9. MetaMask = { Api.Mod4Mask, ModeSwitch };
  10. VAR
  11. event: Api.XEvent; xbuttons: WORDSET;
  12. compstatus: Api.ComposeStatus;
  13. disp: XDisplay.Display;
  14. MMseen, MRseen: BOOLEAN;
  15. TYPE
  16. Poll = OBJECT
  17. BEGIN {ACTIVE, SAFE,PRIORITY(Objects.High - 1)}
  18. LOOP
  19. Objects.Sleep( 15 ); PollXQueue;
  20. END
  21. END Poll;
  22. VAR
  23. poll: Poll; keySymbol: ARRAY 256 OF LONGINT;
  24. PROCEDURE CheckAlternateKeys( VAR mb: SET );
  25. BEGIN
  26. IF ~MMseen & (Api.ControlMask IN xbuttons) THEN INCL( mb, MM ) END;
  27. IF ~MRseen & (Api.Mod1Mask IN xbuttons) THEN INCL( mb, MR ) END
  28. END CheckAlternateKeys;
  29. PROCEDURE SendMouseMsg( x, y, dz: LONGINT; xbuttons: SET );
  30. VAR mm: Inputs.AbsMouseMsg;
  31. BEGIN
  32. Machine.Release( Machine.X11 );
  33. mm.keys := {};
  34. mm.x := x; mm.y := y; mm.dz := dz;
  35. IF Api.Button1Mask IN xbuttons THEN INCL( mm.keys, ML ) END;
  36. IF Api.Button2Mask IN xbuttons THEN INCL( mm.keys, MM ); MMseen := TRUE END;
  37. IF Api.Button3Mask IN xbuttons THEN INCL( mm.keys, MR ); MRseen := TRUE END;
  38. IF ~(MMseen & MRseen) THEN CheckAlternateKeys( mm.keys ) END;
  39. Inputs.mouse.Handle( mm );
  40. Machine.Acquire( Machine.X11 )
  41. END SendMouseMsg;
  42. PROCEDURE SendKeyboardMsg( km: Inputs.KeyboardMsg );
  43. BEGIN
  44. Machine.Release( Machine.X11 );
  45. Inputs.keyboard.Handle( km );
  46. Machine.Acquire( Machine.X11 )
  47. END SendKeyboardMsg;
  48. PROCEDURE PollXQueue;
  49. CONST bufsize = 20;
  50. VAR keycount, xr, yr, x, y, dz, i: LONGINT;
  51. rw, cw: X11.Window;
  52. keysym: X11.KeySym; xd: X11.DisplayPtr;
  53. newxbuttons, bdiff: WORDSET;
  54. km: Inputs.KeyboardMsg;
  55. kp : Api.XKeyEvent;
  56. be : Api.XButtonPressedEvent;
  57. em: Api.XExposeEvent;
  58. cn: Api.XConfigureEvent;
  59. res, events: LONGINT;
  60. buffer: ARRAY bufsize OF CHAR;
  61. msg: LONGINT;
  62. BEGIN
  63. xd := disp.xdisp;
  64. Machine.Acquire( Machine.X11 );
  65. events := Api.Pending( xd );
  66. WHILE events > 0 DO
  67. Api.NextEvent( xd, event );
  68. CASE event.typ OF
  69. | Api.KeyPress: kp := S.VAL( Api.XKeyEvent, event );
  70. X11.lastEventTime := kp.time;
  71. keycount := Api.LookupString( kp, buffer, bufsize, keysym, compstatus );
  72. X11.QueryPointer( xd, event.window, rw, cw, xr, yr, x, y, newxbuttons );
  73. IF keycount = 0 THEN
  74. bdiff := newxbuttons / xbuttons; xbuttons := newxbuttons;
  75. km.ch := 0X;
  76. IF Api.ShiftMask IN bdiff THEN km.keysym := Inputs.KsShiftL
  77. ELSIF Api.ControlMask IN bdiff THEN
  78. km.keysym := Inputs.KsControlL;
  79. IF ~MMseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  80. ELSIF Api.Mod1Mask IN bdiff THEN
  81. km.keysym := Inputs.KsAltL;
  82. IF ~MRseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  83. ELSIF MetaMask*bdiff # {} THEN km.keysym := Inputs.KsMetaL
  84. ELSIF Api.Mod5Mask IN bdiff THEN km.keysym := Inputs.KsAltR
  85. ELSIF keysym = 0FE20H THEN (* handle Shift-Tab key *)
  86. km.keysym := Inputs.KsTab; km.ch :=09X
  87. ELSE
  88. km.keysym := LONGINT(keysym);
  89. END;
  90. km.flags := KeyState( );
  91. SendKeyboardMsg( km )
  92. ELSE
  93. IF (Api.ControlMask IN kp.state) & (keysym = 32) THEN (* check Ctrl-space *)
  94. km.ch := CHR( keysym ); km.flags := KeyState( );
  95. km.keysym := LONGINT(keysym);
  96. SendKeyboardMsg( km ); (* IME keys *)
  97. ELSE
  98. xbuttons := newxbuttons; i := 0;
  99. WHILE i < keycount DO
  100. km.ch := buffer[i];
  101. IF km.ch = 0F1X THEN km.ch := 0A4X
  102. ELSIF km.ch = 0F2X THEN km.ch := 0A5X
  103. END;
  104. km.keysym := keySymbol[ORD( km.ch )];
  105. km.flags := KeyState( );
  106. SendKeyboardMsg( km );
  107. INC( i )
  108. END
  109. END;
  110. END;
  111. | Api.KeyRelease: kp := S.VAL(Api.XKeyEvent, event);
  112. X11.lastEventTime := kp.time;
  113. X11.QueryPointer( xd, event.window, rw, cw, xr, yr, x, y, newxbuttons );
  114. bdiff := newxbuttons / xbuttons; xbuttons := newxbuttons;
  115. IF bdiff # {} THEN
  116. km.ch := 0X;
  117. IF Api.ShiftMask IN bdiff THEN km.keysym := Inputs.KsShiftL
  118. ELSIF Api.ControlMask IN bdiff THEN
  119. km.keysym := Inputs.KsControlL;
  120. IF ~MMseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  121. ELSIF Api.Mod1Mask IN bdiff THEN
  122. km.keysym := Inputs.KsAltL;
  123. IF ~MRseen THEN SendMouseMsg( x, y, 0, xbuttons ) END
  124. ELSIF MetaMask*bdiff # {} THEN km.keysym := Inputs.KsMetaL
  125. ELSIF Api.Mod5Mask IN bdiff THEN km.keysym := Inputs.KsAltR
  126. END;
  127. km.flags := KeyState( ) + {Inputs.Release};
  128. SendKeyboardMsg( km )
  129. END
  130. | Api.ButtonPress: be := S.VAL(Api.XButtonPressedEvent, event);
  131. X11.lastEventTime := be.time;
  132. dz := 0;
  133. CASE be.button OF
  134. | Api.Button1: INCL( xbuttons, Api.Button1Mask )
  135. | Api.Button2: INCL( xbuttons, Api.Button2Mask )
  136. | Api.Button3: INCL( xbuttons, Api.Button3Mask )
  137. | Api.Button4: dz := -1
  138. | Api.Button5: dz := +1
  139. ELSE (* ignore *)
  140. END;
  141. SendMouseMsg( be.x, be.y, dz, xbuttons )
  142. | Api.ButtonRelease: be := S.VAL(Api.XButtonReleasedEvent, event);
  143. X11.lastEventTime := be.time;
  144. CASE be.button OF
  145. | Api.Button1: EXCL( xbuttons, Api.Button1Mask )
  146. | Api.Button2: EXCL( xbuttons, Api.Button2Mask )
  147. | Api.Button3: EXCL( xbuttons, Api.Button3Mask )
  148. ELSE (* ignore *)
  149. END;
  150. SendMouseMsg( be.x, be.y, 0, xbuttons )
  151. | Api.MotionNotify:
  152. X11.QueryPointer( xd, event.window, rw, cw, xr, yr, x, y, xbuttons );
  153. SendMouseMsg( x, y, 0, xbuttons )
  154. | Api.Expose, Api.GraphicsExpose:
  155. (* hacking, clear all expoure events in queue *)
  156. REPEAT res := Api.CheckTypedEvent(xd, Api.Expose, event) UNTIL res # X11.True;
  157. REPEAT
  158. res := Api.CheckWindowEvent(xd, disp.primary, Api.ExposureMask, event)
  159. UNTIL res # X11.True;
  160. em := S.VAL( Api.XExposeEvent, event );
  161. IF em.count = 0 THEN (* wait until last message*)
  162. (* Let DisplayRefresher handle this *)
  163. km.keysym := 0FFC6H;
  164. SendKeyboardMsg( km );
  165. END;
  166. (* clear all expoure events in queue, again *)
  167. REPEAT res := Api.CheckTypedEvent(xd, Api.Expose, event) UNTIL res # X11.True;
  168. | Api.NoExpose:
  169. | Api.MappingNotify:
  170. X11.RefreshKeyboardMapping( ADDRESSOF( event ) )
  171. | Api.ClientMessage:
  172. IF SIZEOF( ADDRESS ) = 8 THEN (* hack to avoid a 64-bit X11Api (alignments are different in C and Oberon) !! *)
  173. S.GET( ADDRESSOF( event ) + 56, msg )
  174. ELSE
  175. S.GET( ADDRESSOF( event ) + 28, msg )
  176. END;
  177. IF msg = disp.wmDelete THEN
  178. (* shutdown *)
  179. Machine.Release( Machine.X11 );
  180. Modules.Shutdown( Modules.Reboot );
  181. END;
  182. | Api.UnmapNotify:
  183. | Api.MapNotify:
  184. | Api.SelectionClear:
  185. IF Api.ClearSelection # NIL THEN Api.ClearSelection(); END
  186. | Api.SelectionNotify:
  187. IF Api.ReceiveSelection # NIL THEN
  188. Machine.Release( Machine.X11 );
  189. Api.ReceiveSelection( S.VAL( Api.XSelectionEvent, event ) );
  190. Machine.Acquire( Machine.X11 )
  191. END
  192. | Api.SelectionRequest:
  193. IF Api.SendSelection # NIL THEN
  194. Machine.Release( Machine.X11 );
  195. Api.SendSelection( S.VAL( Api.XSelectionRequestEvent, event ) );
  196. Machine.Acquire( Machine.X11 )
  197. END
  198. | Api.ConfigureNotify: cn := S.VAL(Api.XConfigureEvent, event);
  199. ELSE
  200. (* ignore *)
  201. END;
  202. events := Api.Pending( xd );
  203. END;
  204. Machine.Release( Machine.X11 );
  205. END PollXQueue;
  206. (* Returns wether key (SHIFT, CTRL or ALT) is pressed *)
  207. PROCEDURE KeyState( ): SET;
  208. VAR keys: SET;
  209. BEGIN
  210. keys := {};
  211. IF Api.ShiftMask IN xbuttons THEN INCL( keys, Inputs.LeftShift ) END;
  212. IF Api.ControlMask IN xbuttons THEN INCL( keys, Inputs.LeftCtrl ) END;
  213. IF Api.Mod1Mask IN xbuttons THEN INCL( keys, Inputs.LeftAlt ) END;
  214. IF MetaMask*xbuttons # {} THEN INCL( keys, Inputs.LeftMeta ) END;
  215. IF Api.Mod5Mask IN xbuttons THEN INCL( keys, Inputs.RightAlt ) END;
  216. RETURN keys
  217. END KeyState;
  218. PROCEDURE Keysym( CONST str: ARRAY OF CHAR ): X11.KeySym;
  219. BEGIN
  220. RETURN X11.StringToKeysym( ADDRESSOF( str ) )
  221. END Keysym;
  222. PROCEDURE Init*;
  223. VAR FK: ARRAY 8 OF CHAR;
  224. n, i, k: LONGINT; modifiers: X11.Modifiers;
  225. shift, control, meta, alt, capslock, numlock: X11.KeySym;
  226. PROCEDURE Rebind( CONST keystr: ARRAY OF CHAR; nofmod: LONGINT; key: CHAR );
  227. VAR newkeystr: ARRAY 8 OF CHAR;
  228. oldkeysym: X11.KeySym;
  229. BEGIN
  230. Machine.Acquire( Machine.X11 );
  231. oldkeysym := Keysym( keystr );
  232. newkeystr[0] := key; newkeystr[1] := 0X;
  233. X11.RebindKeysym( disp.xdisp, oldkeysym, modifiers, nofmod, ADDRESSOF( newkeystr ), 1 );
  234. Machine.Release( Machine.X11 )
  235. END Rebind;
  236. PROCEDURE Rebind4( CONST keyString: ARRAY OF CHAR; n: LONGINT; key: CHAR );
  237. BEGIN
  238. Rebind( keyString, n, key );
  239. modifiers[n] := shift; Rebind( keyString, n + 1, key );
  240. modifiers[n] := control; Rebind( keyString, n + 1, key );
  241. modifiers[n + 1] := shift; Rebind( keyString, n + 2, key );
  242. END Rebind4;
  243. BEGIN
  244. MMseen := FALSE; MRseen := FALSE;
  245. Machine.Acquire( Machine.X11 );
  246. X11.SelectInput( disp.xdisp, disp.primary,
  247. X11.ExposureMask + X11.ButtonPressMask + X11.OwnerGrabButtonMask +
  248. X11.ButtonReleaseMask + X11.PointerMotionHintMask + X11.PointerMotionMask +
  249. X11.KeyPressMask + X11.KeyReleaseMask + X11.StructureNotifyMask );
  250. Machine.Release( Machine.X11 );
  251. shift := Keysym( "Shift_L" ); control := Keysym( "Control_L" );
  252. meta := Keysym( "Meta-L" ); alt := Keysym( "Alt_L" );
  253. capslock := Keysym( "Caps_Lock" ); numlock := Keysym( "Num_Lock" );
  254. modifiers[0] := shift;
  255. Rebind( "Pause", 1, 0ADX ); (* SHIFT-BREAK *)
  256. modifiers[0] := control; Rebind( "Return", 1, 0AX );
  257. modifiers[1] := numlock; Rebind( "Return", 2, 0AX );
  258. modifiers[1] := capslock; Rebind( "Return", 2, 0AX );
  259. modifiers[2] := numlock; Rebind( "Return", 3, 0AX );
  260. FOR k := 0 TO 4 DO
  261. CASE k OF
  262. | 0: n := 0;
  263. | 1: modifiers[0] := meta; n := 1;
  264. | 2: modifiers[0] := capslock; n := 1
  265. | 3: modifiers[0] := numlock; n := 1
  266. | 4: modifiers[0] := capslock; modifiers[1] := numlock; n := 2
  267. END;
  268. i := 0; FK := "F0";
  269. WHILE i < 10 DO FK[1] := CHR( ORD( "0" ) + i ); Rebind4( FK, n, CHR( 0F0H + i ) ); INC( i ) END;
  270. i := 10; FK := "F10";
  271. WHILE i <= 12 DO FK[2] := CHR( ORD( "0" ) + i - 10 ); Rebind4( FK, n, CHR( 0F0H + i ) ); INC( i ) END;
  272. Rebind4( "BackSpace", n, 7FX );
  273. Rebind4( "Delete", n, 0A1X );
  274. Rebind4( "Escape", n, 1BX );
  275. Rebind4( "Up", n, 0C1X ); Rebind4( "Down", n, 0C2X );
  276. Rebind4( "Left", n, 0C4X ); Rebind4( "Right", n, 0C3X );
  277. IF k < 3 THEN
  278. (* do not for NumLock on *)
  279. Rebind4( "KP_Up", n, 0C1X ); Rebind4( "KP_Down", n, 0C2X );
  280. Rebind4( "KP_Left", n, 0C4X ); Rebind4( "KP_Right", n, 0C3X );
  281. END;
  282. Rebind4( "Prior", n, 0A2X ); Rebind4( "KP_Prior", n, 0A2X );
  283. Rebind4( "Next", n, 0A3X ); Rebind4( "KP_Next", n, 0A3X );
  284. Rebind4( "Insert", n, 0A0X );
  285. Rebind4( "Home", n, 0A8X ); Rebind4( "KP_Home", n, 0A8X );
  286. Rebind4( "End", n, 0A9X ); Rebind4( "KP_End", n, 0A9X );
  287. END;
  288. (* special keyboard: *)
  289. modifiers[0] := shift; modifiers[1] := meta;
  290. FOR i := 0 TO 2 DO
  291. Rebind( "aacute", i, 094X );
  292. Rebind( "agrave", i, 08BX );
  293. Rebind( "Adiaeresis", i, 080X ); Rebind( "adiaeresis", i, 083X );
  294. Rebind( "acircumflex", i, 086X );
  295. Rebind( "eacute", i, 090X );
  296. Rebind( "egrave", i, 08CX );
  297. Rebind( "ediaeresis", i, 091X );
  298. Rebind( "ecircumflex", i, 087X );
  299. Rebind( "igrave", i, 08DX );
  300. Rebind( "idiaeresis", i, 092X );
  301. Rebind( "icircumflex", i, 088X );
  302. Rebind( "ograve", i, 08EX );
  303. Rebind( "Odiaeresis", i, 081X ); Rebind( "odiaeresis", i, 084X );
  304. Rebind( "ocircumflex", i, 089X );
  305. Rebind( "ugrave", i, 08FX );
  306. Rebind( "Udiaeresis", i, 082X ); Rebind( "udiaeresis", i, 085X );
  307. Rebind( "ucircumflex", i, 08AX );
  308. Rebind( "ccedilla", i, 093X );
  309. Rebind( "ntilde", i, 095X );
  310. Rebind( "ssharp", i, 096X );
  311. Rebind( "idotless", i, 0FDX);
  312. Rebind( "Iabovedot", i, 0DDX);
  313. Rebind( "gbreve", i, 0F0X );
  314. Rebind( "Gbreve", i, 0D0X );
  315. Rebind( "scedilla", i, 0FEX );
  316. Rebind( "Scedilla", i, 0DEX );
  317. END;
  318. InitKeysym;
  319. NEW( poll );
  320. END Init;
  321. PROCEDURE InitKeysym;
  322. VAR i: LONGINT;
  323. BEGIN
  324. FOR i := 0 TO 255 DO keySymbol[i] := i END;
  325. keySymbol[07FH] := Inputs.KsBackSpace;
  326. keySymbol[009H] := Inputs.KsTab;
  327. keySymbol[00AH] := Inputs.KsReturn;
  328. keySymbol[00DH] := Inputs.KsReturn;
  329. keySymbol[0C1H] := Inputs.KsUp;
  330. keySymbol[0C2H] := Inputs.KsDown;
  331. keySymbol[0C3H] := Inputs.KsRight;
  332. keySymbol[0C4H] := Inputs.KsLeft;
  333. keySymbol[0A0H] := Inputs.KsInsert;
  334. keySymbol[0A1H] := Inputs.KsDelete;
  335. keySymbol[0A2H] := Inputs.KsPageUp;
  336. keySymbol[0A3H] := Inputs.KsPageDown;
  337. keySymbol[0A8H] := Inputs.KsHome;
  338. keySymbol[0A9H] := Inputs.KsEnd;
  339. keySymbol[01BH] := Inputs.KsEscape;
  340. FOR i := 0F1H TO 0FCH DO keySymbol[i] := 0FFBEH + (i - 0F1H) END;
  341. keySymbol[0A4H] := Inputs.KsF1;
  342. keySymbol[0A5H] := Inputs.KsF2;
  343. END InitKeysym;
  344. PROCEDURE GetXDisplay;
  345. VAR p: Plugins.Plugin;
  346. BEGIN
  347. p := Displays.registry.Await( "XDisplay" ); disp := p( XDisplay.Display )
  348. END GetXDisplay;
  349. BEGIN
  350. ASSERT( S.VAL( LONGINT, {0} ) = 1 );
  351. GetXDisplay;
  352. END KbdMouse.
  353. (** Remark:
  354. 1. Keyboard character codes correspond to the ASCII character set. Some other important codes are:
  355. SHIFT-BREAK 0ADX
  356. BREAK 0ACX
  357. F1 ... F12 0F1X ... 0FCX
  358. UP ARROW 0C1X
  359. RIGHT ARROW 0C3X
  360. DOWN ARROW 0C2X
  361. LEFT ARROW 0C4X
  362. INSERT 0A0X
  363. DELETE 0A1X
  364. PAGE-UP 0A2X
  365. PAGE-DOWN 0A3X
  366. some none ascii character get mapped to UTF8:
  367. ä, Ä 131, 128
  368. ö, Ö 132, 129
  369. ü, Ü 133, 130
  370. ß 150
  371. . . .
  372. *)