Unix.KbdMouse.Mod 14 KB

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