Advertisement
Zeus81

Input Ultimate 2.3 fr

Mar 11th, 2012
5,462
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 73.71 KB | None | 0 0
  1. =begin
  2.   Input Ultimate 2.3 by Zeus81
  3.   Free for non-commercial use
  4.  
  5.   Pour simplement régler les touches sans vouloir en savoir plus, aller ligne 1471.
  6.  
  7. REFERENCES
  8.   Input :
  9.     Constantes :
  10.       REPEAT : Permet de régler la façon dont la méthode repeat? fonctionne, ligne 1417.
  11.       PLAYERS_MAX : Le nombre de joueurs gérés par le script, à configurer ligne 1424.
  12.       KEYS_MAX : Définit une limite pour optimiser la mémoire, ligne 1425.
  13.       Players : La liste des contrôles joueurs.
  14.       Gamepads : La liste des manettes détectées.
  15.     Méthodes :
  16.       Input.update : A appeler une fois par frame pour tout mettre à jour.
  17.       Input.refresh : Détecte les manettes connectées au PC.
  18.       Input[i] : Retourne le contrôle du joueur i (commence à 0).
  19.                  Le premier Player est fusionné avec le module Input
  20.                  Faire Input.trigger?(k) équivaut à faire Input[0].trigger?(k)
  21.      
  22.   Device :
  23.       Base commune à Player, Gamepad, Keyboard et Mouse
  24.     Propriétés :
  25.       enabled : Permet d'activer ou désactiver un contrôle.
  26.                 Par exemple si on fait un jeu multijoueur mais qu'on joue en solo
  27.                 on peut désactiver les autres joueurs pour optimiser les perfs.
  28.                 Par défaut tous les contrôles sont activés sauf la souris et les
  29.                 manettes non utilisées.
  30.       ntrigger_max : Option de la fonction ntrigger? décrite plus en dessous.
  31.                      C'est ce qui est utilisé pour les doubles clics de la souris.
  32.                      Par défaut cette option est désactivée (égale à 0) sauf
  33.                      pour la souris où elle est égale à 3 (pour les triples clic).
  34.                      Cette limite sert à faire boucler les clics, par exemple là
  35.                      si je fais 5 clics ça sera considéré comme un triple clic
  36.                      suivi d'un double clic.
  37.       ntrigger_time : Temps en nombre de frames pouvant s'écouler entre deux
  38.                       clics pour être considérés comme une série de clics.
  39.                       Si on met 0 ce temps sera le même que dans Windows. (Défaut)
  40.     Méthodes :
  41.       press?(*a) : Retourne true si la touche est pressée sinon false.
  42.                    La fonction peut être utilisée de plusieurs façons :
  43.                     Input.press?(Input::C)
  44.                     Input.press?(:C)
  45.                     Input.press?('C')
  46.                     Input.press?(13)
  47.                     Input::C.press?
  48.                    Tout ceci revient au même, cela dit en terme de performance
  49.                     Input::C.press? est deux fois plus rapide que les autres.
  50.                    On peut aussi mettre plusieurs touches à la fois :
  51.                     Input.press?(:A, :B, :C) = :A or :B or :C
  52.                    En regroupant des touches dans un tableaux on inverse or/and :
  53.                     Input.press?([:A, :B, :C]) = :A and :B and :C
  54.                    On peut mélanger les deux :
  55.                     Input.press?(:A, [:B, :C]) = :A or (:B and :C)
  56.                    Et mettre plusieurs niveaux de tableaux :
  57.                     Input.press?([:A, [:B, :C]]) = :A and (:B or :C)
  58.                    En plus des tableaux on peut aussi utiliser des Range :
  59.                     Input.press?(:A..:C) = Input.press?([:A, :B, :C])
  60.                     Input.press?(*:A..:C) = Input.press?(:A, :B, :C)
  61.                    Oui je sais, tout ça ne servira absolument à rien.
  62.       trigger?(*a) : Retourne true si la touche vient d'être pressée.
  63.                      Pour les arguments fonctionne comme press?
  64.       release?(*a) : Retourne true si la touche vient d'être relâchée.
  65.                      Pour les arguments fonctionne comme press?
  66.       repeat?(*a) : Retourne true ou false selon le schéma de REPEAT
  67.                     Pour les arguments fonctionne comme press?
  68.       ntrigger?(n,*a) : Retourne true si la touche vient d'être pressée comme
  69.                         trigger? mais en comptant le nombre de fois.
  70.                         Mouse.ntrigger?(2, :Left) retournera true uniquement si
  71.                         on fait un double clic, si ensuite on fait un troisième
  72.                         clic seul Mouse.ntrigger?(3, :Left) retournera true.
  73.                         n doit être inférieur ou égal à ntrigger_max
  74.                         Pour les arguments fonctionne comme press?
  75.       count(k) : Retourne le temps en nombre de frames depuis quand la touche k
  76.                  est pressée, 0 si elle n'est pas pressée.
  77.                  Comme pour le reste k peut être égal à Input::C, :C, 'C', 13.
  78.                  Et on peut aussi écrire Input::C.count
  79.       key(i) : Retourne la touche Key ayant pour id i.
  80.                Ici aussi i peut être un symbole, string, nombre (:C, 'C', 13).
  81.       capture_key(*exclude) : Si jamais vous faites un menu pour configurer les
  82.                               touches utilisez cette fonction pour attendre
  83.                               que le joueur appuie comme ceci :
  84.                                 until key = Keyboard.capture_key || Input.gamepad.capture_key
  85.                                   Graphics.update
  86.                                   Input.update
  87.                                 end
  88.                               key sera un Keyboard_Key ou Gamepad_Key, vous pouvez
  89.                               bien entendu les séparer si vous ne voulez que l'un
  90.                               ou l'autre.
  91.                               Protip, avant d'appeler cette méthode utilisez un
  92.                               release? plutôt qu'un trigger? pour éviter que la
  93.                               touche soit capturée. De même il vaut mieux
  94.                               ensuite attendre que la touche capturée soit
  95.                               relâchée avant de continuer, ce qui donne :
  96.                                 if Input::C.release?
  97.                                   until key = Keyboard.capture_key || Input.gamepad.capture_key
  98.                                     Graphics.update
  99.                                     Input.update
  100.                                   end
  101.                                   while key and key.push?
  102.                                     Graphics.update
  103.                                     Input.update
  104.                                   end
  105.                                 end
  106.                               Vous pouvez aussi mettre en arguments des touches
  107.                               que vous désirez ignorer.
  108.      
  109.   Player < Device :
  110.       Pour les jeux multijoueur on y accède en utilisant Input[i]
  111.       Pour simplifier les jeux solo le premier Player est fusionné avec Input :
  112.         Input.trigger?(*a) = Input[0].trigger?(*a)
  113.     Constantes :
  114.       A, B, C, etc... : Les touches du jeu virtuelles (à ne pas confondre avec
  115.                         les touches du clavier), à configurer ligne 1433.
  116.                         Ce ne sont pas des nombres mais des objets de type Player_Key
  117.                         ce qui permet de faire des chose comme : Input::C.press?
  118.                         Pour les jeux multijoueurs on peut aussi faire :
  119.                           Input::C[i].press? où i est l'id du joueur.
  120.     Propriétés :
  121.       id : Id du joueur. (lecture seule)
  122.       gamepad_id : Id du gamepad, par défaut égal à l'id du joueur.
  123.                    Pour que le joueur n'ai pas de gamepad, mettre la valeur -1.
  124.       gamepad : Contrôleur Gamepad associé au joueur. (lecture seule)
  125.     Méthodes :
  126.       setup(h) : Configure la relation entre les touches virtuelles du jeu et
  127.                  les touches réelles des clavier/manettes.
  128.                  Nécessite un format particulier, voir ligne 1471.
  129.       dir4() : Retourne la direction pressée, format 4 directions.
  130.       dir8() : Retourne la direction pressée, format 8 directions.
  131.       dir360() : Retourne la direction pressée sous forme d'un angle et une
  132.                  pression (pourcentage entre 0 et 1).
  133.                   angle, power = Input.dir360
  134.                  A la base créé pour les joysticks analogiques comme la fonction
  135.                  analog? celle-ci retourne des valeurs aux extrémités si utilisé
  136.                  sans manette analogique.
  137.       dirXY() : Retourne la direction pressée sous forme de deux axes entre -1 et 1.
  138.                   x, y = Input.dirXY
  139.                 Si le stick est orienté vers la gauche x = -1, vers la droite x = 1.
  140.                 Si le stick est orienté vers le bas y = -1, vers le haut y = 1.
  141.                 Par contre attention, la portée d'un joystick n'est pas carrée
  142.                 (ni ronde d'ailleurs, c'est plus un carré aux bords arrondis)
  143.                 de ce fait si on oriente le stick vers bas gauche par exemple
  144.                 on aura pas x, y = -1, -1 mais plus x, y = -0.8, -0.8
  145.      
  146.   Gamepad < Device :
  147.       Il y a trois types de gamepad, Multimedia_Gamepad pour les manettes
  148.       standard, XBox360_Gamepad spécialement pour les manettes Xbox et
  149.       No_Gamepad quand on a aucune manette, toutes ont les mêmes fonctions.
  150.       La classe No_Gamepad est là juste pour qu'on ait pas à se soucier de savoir
  151.       si un pad est branché ou pas avant d'utiliser ses fonctions.
  152.       Par exemple si on veut utiliser la fonction vibrate! on l'utilise, si une
  153.       manette xbox est branchée ça vibrera sinon ça fera rien, pas d'erreur.
  154.     Constantes :
  155.       AXIS_PUSH : Les joysticks analogiques ont une valeur de pression entre
  156.                   0 et 32768 par direction.
  157.                   Cette variable contient la valeur au delà de laquelle ces
  158.                   touches seront considérés comme pressés si on utilise la
  159.                   fonction press? par exemple.
  160.                   Par défaut 16384 (soit 50%), à configurer ligne 679.
  161.       AXIS_DEADZONE : La position de repos d'un joystick analogique (au milieu)
  162.                       n'est pas très stable, par conséquent si on utilise la
  163.                       fonction analog? on obtient jamais 0, une zone morte est
  164.                       établie au centre du joystick pour pallier à ça.
  165.                       Par défaut 6666 (soit 10%), à configurer ligne 679.
  166.       TRIGGER_PUSH : Les gâchettes LT et RT des manettes XBox360 ont une valeur
  167.                      de pression entre 0 et 255.
  168.                      Cette variable contient la valeur au delà de laquelle ces
  169.                      touches seront considérés comme pressés si on utilise la
  170.                      fonction press? par exemple.
  171.                      Par défaut 0, à configurer ligne 679.
  172.       Button1, Button2, etc.. : Les touches standard des manettes, liste ligne 681.
  173.                                 On les utilise uniquement lors du setup des Player.
  174.                                   Gamepad::Button1
  175.       LB, RB, etc... : Les touches des manettes xbox, liste ligne 689.
  176.                        On les utilise uniquement lors du setup des Player.
  177.                         XBox360_Gamepad::A
  178.                        Ça revient au même que d'utiliser les touches standard
  179.                        c'est juste l'écriture qui change, utilisez celle que
  180.                        vous préférez.
  181.      
  182.     Propriétés :
  183.       unplugged : Retourne true si la manette est débranchée. (lecture seule)
  184.                   Ça peut être utilisé pour détecter une perte de manette soudaine.
  185.                   Si on a pas de manette depuis le départ ce n'est pas considéré
  186.                   comme une manette débranchée mais comme une manette de type
  187.                   No_Gamepad avec unplugged = false
  188.       vibration : Permet d'activer ou pas les vibrations.
  189.     Méthodes :
  190.       analog?(*a) : Retourne un pourcentage entre 0 et 1 si la touche pressée est
  191.                     analogique (sticks des manettes et gâchettes LT RT pour les
  192.                     pads xbox) sinon retourne 0 ou 1.
  193.                     Cette fonction est là pour les manettes cela dit on écrira
  194.                     jamais : Input.gamepad.analog?(XBox360_Gamepad::AxisLY_0)
  195.                     Mais plutôt : Input.analog?(Input::DOWN)
  196.                     Les touches de la manette étant liées au setup du Player.
  197.                     Pour les arguments fonctionne comme press?.
  198.       vibrate!(id, speed, fade_in, duration, fade_out) :
  199.                   Fait vibrer la manette, ne fait rien si les vibrations
  200.                   sont désactivées ou que ce n'est pas une manette XBox360.
  201.                   id = 0 ou 1, pour les moteurs gauche ou droite.
  202.                        Ou sinon 2 pour les deux en même temps.
  203.                   speed = pourcentage entre 0 et 1
  204.                   fade_in = durée de la transition entre le niveau de vibration
  205.                             en cours et celui désiré.
  206.                   duration = durée de la vibration.
  207.                   fade_out = durée de la transition vers 0 à la fin du temps.
  208.                   Exemple :
  209.                     Input.gamepad.vibrate!(2, 0.5, 50, 200, 50)
  210.                   Les deux moteurs vibreront à 50% sur en tout 300 frames.
  211.                  
  212.   Keyboard < Device :
  213.       Attention normalement vous ne devriez jamais utiliser le clavier directement.
  214.       Pour créer des jeux il est préférable d'utiliser des touches virtuelles
  215.       qui peuvent correspondre à plusieurs touches du clavier + des manettes en
  216.       même temps et éventuellement être configurable par le joueur,
  217.       donc utilisation directe du clavier à éviter.
  218.       Pour ce qui est de la saisie de texte la classe Text_Entry_Box est là.
  219.     Constantes :
  220.       Escape, Enter, etc... : Les touches du clavier, voir la liste ligne 862.
  221.                               Ce ne sont pas des nombres mais des objets de type
  222.                               Keyboard_Key ce qui permet de faire des chose comme :
  223.                                 Keyboard::Enter.push?
  224.     Méthodes :
  225.       setup(*a) : Si toutefois vous étiez amené pour une raison ou une autre à
  226.                   devoir malgré tout utiliser directement le clavier, il faudra
  227.                   d'abord lui dire quelles touches mettre à jour.
  228.                   Par défaut aucune n'est mise à jour parce que ça prendrait du
  229.                   temps pour rien.
  230.                   Comme pour le reste plusieurs écritures sont supportées :
  231.                     Keyboard.setup(Keyboard::Enter, :Escape, 'A'..'Z', 1)
  232.                   Pour désactiver la mise à jour des touches :
  233.                     Keyboard.setup()
  234.                   A chaque setup toutes les touches envoyées remplacent les
  235.                   anciennes, elles ne s'ajoutent pas.
  236.                   Cependant vous n'avez besoin de faire ça que si vous désirez
  237.                   utiliser les fonctions press?, trigger?, release?, repeat?,
  238.                   ntrigger? et count, les fonctions push?, toggle?, push!, release!
  239.                   et toggle! si dessous peuvent être utilisées sur n'importe
  240.                   quelle touche en permanence.
  241.       push?(*a) : Fonctionne exactement comme la fonction press? mais en regardant
  242.                   directement l'état du matériel donc un peu plus lentement.
  243.                   A n'utiliser que dans le cas cité précédemment, si vous voulez
  244.                   l'état press d'une touche du clavier sans vouloir passer par
  245.                   le setup, sinon il est préférable d'utiliser press?
  246.                   Vous pouvez aussi l'utiliser sur les constantes Key du clavier :
  247.                     Keyboard::Escape.push?
  248.       toggle?(*a) : Retourne true si la touche est verrouillée sinon false.
  249.                     Le vérouillage est ce qui est utilisé pour les touches
  250.                     Verr. Num, Verr. Maj et Verr. Défil pour savoir si elles
  251.                     sont sur On ou Off, mais vous pouvez l'utiliser sur n'importe
  252.                     quelle touche en fait.
  253.                     Comme push? cette fonction regarde directement l'état du
  254.                     matériel et peut être utilisée sans setup.
  255.                     Vous pouvez aussi l'utiliser sur les constantes Key du clavier :
  256.                       Keyboard::CapsLock.toggle?
  257.                     Pour les arguments fonctionne comme press?
  258.       push!(*a) : Appuie sur les touches du clavier à la place du joueur.
  259.                   Les signaux sont envoyés directement à Windows donc attention.
  260.                   Vous pouvez par exemple forcer le passage en plein écran :
  261.                     Keyboard.push!(:Alt, :Enter)
  262.                   Vous pouvez aussi l'utiliser sur les constantes Key du clavier :
  263.                     Keyboard::Space.push!
  264.                   Pour les arguments fonctionne comme press?
  265.       release!(*a) : Relâche les touches du clavier.
  266.                      Après avoir appeler push! il faut appeler release! pour que
  267.                      le système comprenne qu'elle n'est pas appuyée en permanence.
  268.                      Ce n'est pas automatique !
  269.                      Donc pour finaliser le passage en mode plein écran il faut faire :
  270.                       Keyboard.push!(:Alt, :Enter)
  271.                       Keyboard.release!(:Alt, :Enter)
  272.                      Vous pouvez aussi l'utiliser sur les constantes Key du clavier :
  273.                       Keyboard::Space.release!
  274.                      Pour les arguments fonctionne comme press?
  275.       toggle!(*a) : Change l'état de verrouillage d'une touche.
  276.                     Vous pouvez aussi l'utiliser sur les constantes Key du clavier :
  277.                       Keyboard::Space.release!
  278.                     Pour les arguments fonctionne comme press?
  279.       key_name(k) : Retourne le nom de la touche dans la langue du système.
  280.                     Comme pour press?, k peut être égal à Keyboard::W, :W, 'W', 87.
  281.                     Par exemple : Keyboard.key_name(:Escape) # => "ECHAP"
  282.                     Cependant les noms de toutes les touches ne sont pas forcément
  283.                     bienvenus donc il est peut être préférable de s'organiser
  284.                     soi-même une liste de noms manuellement.
  285.                     Vous pouvez aussi l'utiliser sur les constantes Key du clavier :
  286.                       Keyboard::Escape.name
  287.      
  288.   Mouse < Device :
  289.       Par défaut la souris est désactivée, pour l'activer faites :
  290.         Mouse.enabled = true
  291.     Constantes :
  292.       Left, Middle, Right, X1, X2, WheelUp, WheelDown :
  293.         Les touches de la souris, j'ai tout mis inutile d'aller voir la liste ligne 990.
  294.         Ce ne sont pas des nombres mais des objets de type Mouse_Key ce qui
  295.         permet de faire des chose comme : Mouse::Left.click?
  296.         Left, Middle, Right sont les clics gauche, milieu, droit.
  297.         X1 et X2 sont les boutons sur les côtés de la souris (si y'en a).
  298.         WheelUp et WheelDown pour la roulette ne répondent malheureusement pas
  299.         parfaitement, à éviter dans un jeu du coup, d'ailleurs pour que ça marche
  300.         un tant soit peu il faut mettre le Input.update avant le Graphics.update
  301.     Propriétés :
  302.       click_max : alias de ntrigger_max
  303.                   Contrairement aux autres contrôles le click_max/ntrigger_max
  304.                   de la souris est par défaut égal à 3.
  305.       click_time : alias de ntrigger_time
  306.       cursor : Le curseur de la souris, c'est un Sprite classique donc vous
  307.                pouvez utiliser toutes les fonctions des sprites.
  308.                Pour modifier le curseur par défaut voir ligne 1024.
  309.       x : Raccourci de cursor.x pour la lecture.
  310.           Vous pouvez aussi modifier manuellement la position de la souris.
  311.             Mouse.x = 123
  312.           Attention Mouse.cursor.x = 123 ne fonctionne pas.
  313.       y : Raccourci de cursor.y pour la lecture.
  314.           Vous pouvez aussi modifier manuellement la position de la souris.
  315.             Mouse.y = 456
  316.           Attention Mouse.cursor.y = 456 ne fonctionne pas.
  317.       drag : Le rectangle de sélection utilise aussi un Sprite mais a un
  318.              fonctionnement particulier.
  319.              Il apparait automatiquement quand on maintient un clic gauche et
  320.              déplace la souris, cependant par défaut il est désactivé.
  321.              Si vous désirez changer l'apparence du rectangle de sélection sachez
  322.              que c'est un Bitmap de 1x1 pixels, par défaut il est bleu transparent
  323.              voir ligne 1032, mais on peut le changer à tout moment :
  324.               Mouse.drag.bitmap.set_pixel(0, 0, Color.new(255, 0, 0, 128))
  325.       drag_enabled = Permet d'activer/désactiver la sélection, par défaut désactivée.
  326.                      Pour l'activer : Mouse.drag_enabled = true
  327.       drag_x : Raccourci de drag.x (Lecture seule)
  328.       drag_y : Raccourci de drag.y (Lecture seule)
  329.       drag_width : Largeur de la sélection, équivalent de drag.zoom_x.to_i (Lecture seule)
  330.       drag_height : Hauteur de la sélection, équivalent de drag.zoom_y.to_i (Lecture seule)
  331.       drag_rect : Retourne Rect.new(drag_x, drag_y, drag_width, drag_height) (Lecture seule)
  332.       drag_auto_clear : Si activé la sélection s'effacera automatiquement
  333.                         dès lors qu'on relâche le clic gauche.
  334.       drag_start_size : Nombre de pixels dont on doit déplacer la souris pour
  335.                         faire apparaître le rectangle de sélection, par défaut 10.
  336.     Méthodes :
  337.       icon(s=nil, ox=0, oy=0) : Permet de changer l'apparence du curseur,
  338.                                 l'image doit se trouver dans le dossier picture,
  339.                                 l'extension est facultative.
  340.                                   Mouse.icon("croix")
  341.                                 On peut éventuellement préciser un décalage vers
  342.                                 le centre du curseur si nécessaire, en comptant
  343.                                 à partir du coin haut gauche de l'image.
  344.                                   Mouse.icon("croix", 4, 4)
  345.                                 Si on veut remettre le curseur par défaut :
  346.                                   Mouse.icon()
  347.       clip(*a) : Définit la zone dans laquelle la souris est libre de se mouvoir.
  348.                  Il y a quatre façons d'utiliser cette fonction :
  349.                   Mouse.clip(i) : Si i = 0, aucune limitation, la souris peut
  350.                                   voguer librement sur tout l'écran. (Défaut)
  351.                                   Si i = 1, la souris est bloquée dans la fenêtre
  352.                                   du jeu, càd surface de jeu + barre de titre.
  353.                                   Si i = 2, la souris est bloquée dans la surface
  354.                                   de jeu, on ne peut plus aller sur la barre de titre.
  355.                                   Déconseillé vu qu'on ne peut plus réduire/fermer
  356.                                   le jeu ce qui peut vite devenir pénible.
  357.                   Mouse.clip() : Idem que Mouse.clip(0).
  358.                   Mouse.clip(x, y, w, h) : Définit une zone manuellement,
  359.                                            le point 0, 0 correspond au coin
  360.                                            haut gauche de la surface de jeu.
  361.                   Mouse.clip(rect) : Idem mais avec un objet de type Rect.
  362.       on?(*a) : Retourne true si la souris est dans la zone demandée.
  363.                 Il y a cinq façons d'utiliser cette fonction :
  364.                   Mouse.on?() : vérifie si le curseur est dans la surface de jeu.
  365.                   Mouse.on?(x, y) : vérifie si le curseur est sur le point x y.
  366.                   Mouse.on?(x, y, r) : vérifie si le curseur est dans le cercle
  367.                                        de centre x y et de rayon r.
  368.                   Mouse.on?(x, y, w, h) : vérifie si le curseur est dans le
  369.                                           rectangle aux coordonnées spécifiées.
  370.                   Mouse.on?(rect) : Idem mais avec un objet de type Rect.
  371.       drag_on?(*a) : Retourne true si la sélection est en contact avec la zone donnée.
  372.                      Il y a quatre façons d'utiliser cette fonction :
  373.                       Mouse.drag_on?(x, y) : vérifie si le point x y est compris
  374.                                              dans la sélection.
  375.                       Mouse.drag_on?(x, y, r) : vérifie si le cercle de centre x y
  376.                                                 et de rayon r entre en contact
  377.                                                 avec la sélection.
  378.                       Mouse.drag_on?(x, y, w, h) : vérifie si le rectangle entre
  379.                                                    en contact avec la sélection.
  380.                       Mouse.drag_on?(rect) : Idem mais avec un objet de type Rect.
  381.       drag_clear() : Efface la sélection.
  382.       dragging?() : Retourne true si une sélection est en cours.
  383.       swap_button(b) : Si b = true, inverse les clics gauches et droits,
  384.                        si b = false, les remet à la normale.
  385.       click?(k=Left) : Simple clic, équivalent de ntrigger?(1, k).
  386.                        L'argument est facultatif et est le clic gauche par défaut.
  387.                        La différence entre click? et trigger? est que si on fait
  388.                        un double clic par exemple lors du deuxième clic trigger?
  389.                        renverra true alors que click? false (et dclick? true).
  390.                        Vous pouvez aussi l'utiliser sur les constantes Key de la souris :
  391.                         Mouse::Left.click?
  392.       dclick?(k=Left) : Double clic, équivalent de ntrigger?(2, k).
  393.                         Vous pouvez aussi l'utiliser sur les constantes Key de la souris :
  394.                           Mouse::Left.dclick?
  395.       tclick?(k=Left) : Triple clic, équivalent de ntrigger?(3, k).
  396.                         Vous pouvez aussi l'utiliser sur les constantes Key de la souris :
  397.                           Mouse::Left.tclick?
  398.      
  399.   Key :
  400.       Il y en a quatre types : Player_Key, Gamepad_Key, Keyboard_Key et Mouse_Key
  401.       Certaines possèdent des fonctions en plus.
  402.     Méthodes :
  403.       to_s() : Retourne le nom de la constante.
  404.                 Input::DOWN.to_s # => "DOWN"
  405.       to_i() : Retourne l'id de la touche.
  406.                 Input::DOWN.to_i # => 2
  407.       push?(), toggle?(), press?(), trigger?(), release?(), repeat?(), analog?(),
  408.       ntrigger?(n), count() : Toutes les fonctions décrites précédemment sont
  409.                               utilisables directement sur les touches pour plus
  410.                               d'efficacité :
  411.                                 Input::DOWN.press?
  412.                               Cependant inutile d'appeler ces fonctions sur les
  413.                               touches Gamepad_Key, ça ne marchera pas.
  414.       name(), push!(), release!(), toggle!() : Fonctions supplémentaires des Keyboard_Key
  415.       click?(), dclick?(), tclick?() : Fonctions supplémentaires des Mouse_Key
  416.       [i] : Fonction supplémentaire des Player_Key pour le jeu multijoueur :
  417.               Input::DOWN[0].trigger? # joueur 1
  418.               Input::DOWN[1].trigger? # joueur 2
  419.      
  420.   Text_Entry_Box < Sprite
  421.       Cette classe permet de saisir du texte au clavier, la souris est aussi
  422.       supportée pour la sélection de texte.
  423.       Text_Entry_Box est dérivée de Sprite et son affichage est automatisé.
  424.       Vous pouvez utiliser toutes les fonctions de Sprite cependant les fonctions
  425.       zoom, angle, mirror, src_rect ne seront pas compatibles avec la souris.
  426.       Si la souris est activée et survole une boite de texte, l’icône changera
  427.       automatiquement, vous pouvez modifier son apparence ligne 1180.
  428.     Propriétés :
  429.       enabled : Permet d'activer ou désactiver une boite de texte.
  430.                 Une boite désactivée ne peut plus avoir le focus.
  431.       focus : L'état de focus actuel, une seule boite peut l'avoir à la fois.
  432.       text : Permet de récupérer le texte entré.
  433.       back_color : La couleur du fond, valeur par défaut ligne 1195.
  434.                    Elle peut être modifiée à tout moment mais il faut ensuite
  435.                    appeler refresh() pour mettre à jour le bitmap.
  436.                     text_entry_box.back_color = Color.new(255, 0, 0)
  437.       select_color : Couleur de la sélection, idem que back_color.
  438.       allow_c : Liste des caractères autorisés sous forme de string.
  439.                   text_entry_box.allow_c = "abcABC123"
  440.                 Si la liste est vide tous les caractères sont autorisés. (Défaut)
  441.       select : Permet d'activer ou désactiver les sélections que ce soit avec la
  442.                souris ou en maintenant la touche Maj.
  443.                Activé par défaut, pour le désactiver : text_entry_box.select = false
  444.       mouse : Permet d'activer ou désactiver les fonctionnalités de la souris.
  445.               Activé par défaut, pour le désactiver : text_entry_box.mouse = false
  446.               Il faut aussi que la souris elle même soit activée sinon ça sert à rien.
  447.       case : Casse de caractère :
  448.               text_entry_box.case = 0 # normal, sensible à la casse (Défaut)
  449.               text_entry_box.case = 1 # downcase, les majuscules deviennent minuscules.
  450.               text_entry_box.case = 2 # upcase, les minuscules deviennent majuscules.
  451.       size : Le nombre de caractères actuel. (lecture seule)
  452.       size_max : Le nombre de caractères maximum autorisé.
  453.                  Si 0, pas de limite.
  454.       width : Raccourci pour text_entry_box.bitmap.width (lecture seule)
  455.       width_max : La taille maximum autorisée en pixels.
  456.                   Si 0, pas de limite.
  457.       height : Raccourci pour text_entry_box.bitmap.height (lecture seule)
  458.       font : Raccourci pour text_entry_box.bitmap.font
  459.     Méthodes :
  460.       Text_Entry_Box.new(width, height, viewport=nil) :
  461.           Crée une nouvelle instance de Text_Entry_Box
  462.           On est obligé de préciser width et height qui sont utilisés pour créer
  463.           le bitmap, viewport est facultatif.
  464.             text_entry_box = Text_Entry_Box.new(100, 20)
  465.            
  466.       dispose : Supprime le sprite et le bitmap.
  467.       update : A appeler une fois par frame pour mettre à jour la saisie de texte.
  468.       refresh : A appeler après avoir modifié les propriétés ou le font du bitmap
  469.                 pour forcer la mise à jour.
  470.       hover? : Retourne true si la souris survole la boite texte.
  471.       focus! : Donne le focus à la boite texte, une seule boite peut avoir le
  472.                focus à la fois, il est automatiquement retiré des autres.
  473.                Cette fonction est automatiquement appelée quand on clique sur la
  474.                boite texte, si la souris est activée bien sûr.
  475. =end
  476.  
  477. class Object
  478.   remove_const(:Input)
  479.   def singleton_attach_methods(o) class << self; self end.attach_methods(o) end
  480.   def self.attach_methods(o)
  481.     @attached_methods ||= []
  482.     for m in o.public_methods-(instance_methods-@attached_methods)
  483.       define_method(m, &o.method(m))
  484.       @attached_methods << m unless @attached_methods.include?(m)
  485.     end
  486.   end
  487. end
  488.  
  489. class String; alias getbyte [] end if RUBY_VERSION == '1.8.1'
  490.  
  491. module Input
  492.   class Key
  493.     include Comparable
  494.     attr_reader :o, :i, :s, :hash, :to_sym
  495.     alias to_i i
  496.     alias to_s s
  497.     def initialize(i,o)
  498.       @o, self.i, self.s = o, i, "#{self.class.name.split('::')[-1]}_#{i}"
  499.     end
  500.     def o=(o) @o, @hash = o, @i.hash^o.hash  end
  501.     def i=(i) @i, @hash = i, i.hash^@o.hash  end
  502.     def s=(s) @s, @to_sym = s, s.to_sym      end
  503.     def <=>(o)       @i <=> o.to_i           end
  504.     def succ()       self.class.new(@i+1,@o) end
  505.     def count()      @o.get_count(@i)        end
  506.     def push?()      @o.get_push(@i)         end
  507.     def toggle?()    @o.get_toggle(@i)       end
  508.     def press?()     @o.get_press(@i)        end
  509.     def trigger?()   @o.get_trigger(@i)      end
  510.     def release?()   @o.get_release(@i)      end
  511.     def repeat?()    @o.get_repeat(@i)       end
  512.     def ntrigger?(n) @o.get_ntrigger(n,@i)   end
  513.     def analog?()    @o.get_analog(@i)       end
  514.   end
  515.   class Gamepad_Key < Key
  516.     def initialize(i,o=Gamepad) super        end
  517.   end
  518.   class Keyboard_Key < Key
  519.     def initialize(i,o=Keyboard) super       end
  520.     def name()       @o.get_key_name(@i)     end
  521.     def push!()      @o.push!(@i)            end
  522.     def release!()   @o.release!(@i)         end
  523.     def toggle!()    @o.toggle!(@i)          end
  524.   end
  525.   class Mouse_Key < Key
  526.     def initialize(i,o=Mouse) super          end
  527.     def click?()     ntrigger?(1)            end
  528.     def dclick?()    ntrigger?(2)            end
  529.     def tclick?()    ntrigger?(3)            end
  530.   end
  531.   class Player_Key < Key
  532.     def [](i)        @players_keys[i]        end
  533.     def initialize(i,o=Players[0])
  534.       super
  535.       @players_keys = Players.map {|p| k = dup; k.o = p; k}
  536.     end
  537.   end
  538.  
  539.   class Device
  540.     GetDoubleClickTime = Win32API.new('user32', 'GetDoubleClickTime', '', 'i')
  541.     attr_accessor :enabled, :ntrigger_max, :ntrigger_time
  542.     def initialize(max)
  543.       @enabled, @count, @release, @keys = true, Array.new(max,0), [], []
  544.       @ntrigger_count, @ntrigger_last, @ntrigger_max = @count.dup, @count.dup, 0
  545.       self.ntrigger_time = 0
  546.     end
  547.     def update
  548.       return unless @enabled
  549.       update_keys
  550.       update_ntrigger if @ntrigger_max != 0
  551.     end
  552.     def update_keys
  553.       @release.clear
  554.       for i in @keys
  555.         if    get_push(i)   ; @count[i] += 1
  556.         elsif @count[i] != 0; @count[i]  = 0; @release << i
  557.         end
  558.       end
  559.     end
  560.     def update_ntrigger
  561.       f = Graphics.frame_count
  562.       for i in @keys
  563.         if @count[i] == 1
  564.           @ntrigger_count[i] %= @ntrigger_max
  565.           @ntrigger_count[i] += 1
  566.           @ntrigger_last[i] = f + @ntrigger_time
  567.         elsif @ntrigger_last[i] == f
  568.           @ntrigger_count[i] = 0
  569.         end
  570.       end
  571.     end
  572.     def capture_key(*exclude)
  573.       exclude = keyarrayize(*exclude) unless exclude.empty?
  574.       (@count.size-1).downto(0) {|i| return key(i) if !exclude.include?(i) and get_push(i)}
  575.       nil
  576.     end
  577.     def get_count(i)      @count[i]                                                            end
  578.     def get_push(i)       false                                                                end
  579.     def get_toggle(i)     false                                                                end
  580.     def get_press(i)      @count[i] != 0                                                       end
  581.     def get_trigger(i)    @count[i] == 1                                                       end
  582.     def get_release(i)    @release.include?(i)                                                 end
  583.     def get_repeat(i)     (j=@count[i])>0 and REPEAT.any? {|w,f| break(f>0 && j%f==0) if j>=w} end
  584.     def get_ntrigger(n,i) get_trigger(i) and @ntrigger_count[i] == n                           end
  585.     def get_analog(i)     get_push(i) ? 1.0 : 0.0                                              end
  586.     def count(k)          get_count(k2i(k))                                                           end
  587.     def push?(*a)         a.any?{|i| enum?(i) ? i.all?{|j| push?(*j)}       : get_push(k2i(i))}       end
  588.     def toggle?(*a)       a.any?{|i| enum?(i) ? i.all?{|j| toggle?(*j)}     : get_toggle(k2i(i))}     end
  589.     def press?(*a)        a.any?{|i| enum?(i) ? i.all?{|j| press?(*j)}      : get_press(k2i(i))}      end
  590.     def trigger?(*a)      a.any?{|i| enum?(i) ? i.all?{|j| trigger?(*j)}    : get_trigger(k2i(i))}    end
  591.     def release?(*a)      a.any?{|i| enum?(i) ? i.all?{|j| release?(*j)}    : get_release(k2i(i))}    end
  592.     def repeat?(*a)       a.any?{|i| enum?(i) ? i.all?{|j| repeat?(*j)}     : get_repeat(k2i(i))}     end
  593.     def ntrigger?(n,*a)   a.any?{|i| enum?(i) ? i.all?{|j| ntrigger?(n,*j)} : get_ntrigger(n,k2i(i))} end
  594.     def analog?(*a)
  595.       a.each do |i|
  596.         d = if enum?(i)
  597.           sum = size = 0
  598.           i.each {|j| sum, size = sum+analog?(*j), size+1}
  599.           sum == 0 ? 0 : sum / size
  600.         else get_analog(k2i(i))
  601.         end
  602.         return d if d != 0
  603.       end
  604.       0.0
  605.     end
  606.     def ntrigger_time=(i) @ntrigger_time = (i==0 ? GetDoubleClickTime.call *
  607.                           Graphics.frame_rate / 1000 : i)  end
  608.     def key(o)            self.class.key(o)                end
  609.     def k2i(o)            self.class.k2i(o)                end
  610.   private
  611.     def enum?(o)          o.is_a?(Array) or o.is_a?(Range) end
  612.     def keyarrayize(*a)
  613.       a.flatten!
  614.       a.map! {|o| o.is_a?(Range) ? o.to_a : o}.flatten!
  615.       a.compact!
  616.       a.map! {|k| k2i(k)}.uniq!
  617.       a
  618.     end
  619.     def self.key(o) o.is_a?(Key) || o.is_a?(Integer) ? const_get(:Keys)[o.to_i] : const_get(o) end
  620.     def self.k2i(o) o.is_a?(Key) ? o.i : o.is_a?(Integer) ? o : const_get(o).i                 end
  621.   end
  622.  
  623.   class Player < Device
  624.     attr_reader :id, :gamepad, :gamepad_id
  625.     def initialize(id)
  626.       super(KEYS_MAX)
  627.       @id, @gamepad_id, @gamepad, @map = id, id, No_Gamepad.new, @count.map{[]}
  628.     end
  629.     def setup(h)
  630.       @keys.clear
  631.       @count.fill(0)
  632.       @map.fill([])
  633.       for i,a in h
  634.         a=@map[i=k2i(i)] = a[0].map {|j| Gamepad.key(j).dup} + a[1].map {|j| Keyboard.key(j)}
  635.         @keys << i unless a.empty?
  636.       end
  637.       self.gamepad_id += 0
  638.     end
  639.     def gamepad_id=(i)
  640.       vibration, @gamepad.enabled = @gamepad.vibration, false
  641.       @gamepad = (@gamepad_id = i) >= 0 && Gamepads[i] || No_Gamepad.new
  642.       @gamepad.vibration = vibration
  643.       Players.each {|p| p.gamepad.enabled = true}
  644.       @map.each {|a| a.each {|k| k.o = @gamepad if k.is_a?(Gamepad_Key)}}
  645.     end
  646.     def get_push(i)   @map[i].any? {|k| k.push?}                              end
  647.     def get_toggle(i) @map[i].any? {|k| k.toggle?}                            end
  648.     def get_analog(i) @map[i].each {|k| d=k.analog?; return d if d != 0}; 0.0 end
  649.     def dirXY
  650.       return 0.0, 0.0 unless @enabled
  651.       return RIGHT.analog?-LEFT.analog?, UP.analog?-DOWN.analog?
  652.     end
  653.     def dir360
  654.       x, y = *dirXY
  655.       return 0.0, 0.0 if x == 0 and y == 0
  656.       return Math.atan2(y,x)*180/Math::PI, (w=Math.hypot(x,y))>1 ? 1.0 : w
  657.     end
  658.     def dir8
  659.       d = 5
  660.       d -= 3 if DOWN.press?
  661.       d -= 1 if LEFT.press?
  662.       d += 1 if RIGHT.press?
  663.       d += 3 if UP.press?
  664.       d == 5 ? 0 : d
  665.     end
  666.     def dir4
  667.       case d = dir8
  668.       when 1; DOWN.trigger? == (@last_dir==2) ? 2 : 4
  669.       when 3; DOWN.trigger? == (@last_dir==2) ? 2 : 6
  670.       when 7; UP.trigger?   == (@last_dir==8) ? 8 : 4
  671.       when 9; UP.trigger?   == (@last_dir==8) ? 8 : 6
  672.       else    @last_dir = d
  673.       end
  674.     end
  675.   end
  676.  
  677.   class Gamepad < Device
  678.     ::Gamepad = self
  679.     AXIS_PUSH, AXIS_DEADZONE, TRIGGER_PUSH = 16384, 6666, 0
  680.     Keys = Array.new(48) {|i| Gamepad_Key.new(i)}
  681.     Button1 , Button2 , Button3 , Button4 , Button5 , Button6 , Button7 ,
  682.     Button8 , Button9 , Button10, Button11, Button12, Button13, Button14,
  683.     Button15, Button16, Button17, Button18, Button19, Button20, Button21,
  684.     Button22, Button23, Button24, Button25, Button26, Button27, Button28,
  685.     Button29, Button30, Button31, Button32, Axis1_0 , Axis1_1 , Axis2_0 ,
  686.     Axis2_1 , Axis3_0 , Axis3_1 , Axis4_0 , Axis4_1 , Axis5_0 , Axis5_1 ,
  687.     Axis6_0 , Axis6_1 , PovUp   , PovRight, PovDown , PovLeft = *Keys
  688.     XKeys = Array.new(48) {|i| Gamepad_Key.new(i)}
  689.     A, B, X, Y, LB, RB, LT, RT, BACK, START, LS, RS,
  690.     n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n,
  691.     AxisLX_0, AxisLX_1, AxisLY_1, AxisLY_0, AxisRX_0, AxisRX_1, AxisRY_1, AxisRY_0,
  692.     n, n, n, n, DPadUp, DPadRight, DPadDown, DPadLeft = *XKeys
  693.     constants.each {|s| k = const_get(s);  k.s = s.to_s if k.is_a?(Key)}
  694.    
  695.     attr_accessor :vibration
  696.     attr_reader   :unplugged
  697.     def initialize(id=nil)
  698.       super(48)
  699.       @id, @unplugged, @map, @vibration = id, false, @count.map{[]}, true
  700.     end
  701.     def get_push(i)
  702.       return false unless @enabled and !@unplugged
  703.       j, k = *@map[i]
  704.       case j
  705.       when :button ; button(k)
  706.       when :pov    ; k.include?(pov)
  707.       when :axis_0 ; axis_raw(k) < -AXIS_PUSH
  708.       when :axis_1 ; axis_raw(k) > AXIS_PUSH-1
  709.       when :trigger; trig_raw(k) > TRIGGER_PUSH
  710.       else           false
  711.       end
  712.     end
  713.     def get_analog(i)
  714.       return 0.0 unless @enabled and !@unplugged
  715.       j, k = *@map[i]
  716.       case j
  717.       when :button, :pov; super
  718.       when :axis_0 ; (k=axis_pct(k)) < 0 ? -k : 0.0
  719.       when :axis_1 ; (k=axis_pct(k)) > 0 ?  k : 0.0
  720.       when :trigger; trig_pct(k)
  721.       else           0.0
  722.       end
  723.     end
  724.     def vibrate!(id, speed, fade_in, duration, fade_out) end
  725.   private
  726.     def axis_pct(i)
  727.       (i=axis_raw(i)).abs <= AXIS_DEADZONE ? 0.0 :
  728.       (i<0 ? i+AXIS_DEADZONE : i-AXIS_DEADZONE+1) / (32768.0-AXIS_DEADZONE)
  729.     end
  730.     def trig_pct(i) trig_raw(i) / 255.0 end
  731.     def axis_raw(i) 0                   end
  732.     def trig_raw(i) 0                   end
  733.     def pov()       0                   end
  734.     def button(i)   false               end
  735.      
  736.     singleton_attach_methods(@o = new)
  737.    
  738.     class No_Gamepad < Gamepad
  739.       ::No_Gamepad = Input::No_Gamepad = self
  740.       def get_push(i)   false end
  741.       def get_analog(i) 0.0   end
  742.     end
  743.    
  744.     class Multimedia_Gamepad < Gamepad
  745.       ::Multimedia_Gamepad = Input::Multimedia_Gamepad = self
  746.       JoyGetDevCaps = Win32API.new('winmm', 'joyGetDevCaps', 'ipi', 'i')
  747.       JoyGetPosEx   = Win32API.new('winmm', 'joyGetPosEx'  , 'ip' , 'i')
  748.       def initialize(id)
  749.         super
  750.         JoyGetDevCaps.call(id, devcaps="\0"*404, 404)
  751.         @caps = Array.new(7) {|i| i<2 or devcaps.getbyte(96)[i-2]==1}
  752.         @buffer = [52,255,0,0,0,0,0,0,0,0,0,0,0].pack('L13')
  753.         @state = @buffer.unpack('L13')
  754.         for k,v in {            Button1 =>[:button, 0], Button2 =>[:button, 1],
  755.         Button3 =>[:button, 2], Button4 =>[:button, 3], Button5 =>[:button, 4],
  756.         Button6 =>[:button, 5], Button7 =>[:button, 6], Button8 =>[:button, 7],
  757.         Button9 =>[:button, 8], Button10=>[:button, 9], Button11=>[:button,10],
  758.         Button12=>[:button,11], Button13=>[:button,12], Button14=>[:button,13],
  759.         Button15=>[:button,14], Button16=>[:button,15], Button17=>[:button,16],
  760.         Button18=>[:button,17], Button19=>[:button,18], Button20=>[:button,19],
  761.         Button21=>[:button,20], Button22=>[:button,21], Button23=>[:button,22],
  762.         Button24=>[:button,23], Button25=>[:button,24], Button26=>[:button,25],
  763.         Button27=>[:button,26], Button28=>[:button,27], Button29=>[:button,28],
  764.         Button30=>[:button,29], Button31=>[:button,30], Button32=>[:button,31],
  765.         Axis1_0 =>[:axis_0, 0], Axis1_1 =>[:axis_1, 0], Axis2_0 =>[:axis_0, 1],
  766.         Axis2_1 =>[:axis_1, 1], Axis3_0 =>[:axis_0, 2], Axis3_1 =>[:axis_1, 2],
  767.         Axis4_0 =>[:axis_0, 3], Axis4_1 =>[:axis_1, 3], Axis5_0 =>[:axis_0, 4],
  768.         Axis5_1 =>[:axis_1, 4], Axis6_0 =>[:axis_0, 5], Axis6_1 =>[:axis_1, 5],
  769.         PovUp   =>[:pov,[31500,    0, 4500]], PovRight=>[:pov,[ 4500, 9000,13500]],
  770.         PovDown =>[:pov,[13500,18000,22500]], PovLeft =>[:pov,[22500,27000,31500]]}
  771.           @map[k.i] = v
  772.         end
  773.         update
  774.       end
  775.       def update
  776.         return unless @enabled and !@unplugged = JoyGetPosEx.call(@id, @buffer) != 0
  777.         @state.replace(@buffer.unpack('L13'))
  778.         super
  779.       end
  780.     private
  781.       def button(i)   @state[8][i] == 1                end
  782.       def pov()       @caps[6] ? @state[10] : 0        end
  783.       def axis_raw(i) @caps[i] ? @state[2+i]-32768 : 0 end
  784.     end
  785.    
  786.     class XBox360_Gamepad < Gamepad
  787.       ::XBox360_Gamepad = Input::XBox360_Gamepad = self
  788.       Keys = XKeys
  789.       XInputGetState = (Win32API.new(DLL='xinput1_3'  , 'XInputGetState', 'ip', 'i') rescue
  790.                         Win32API.new(DLL='xinput1_2'  , 'XInputGetState', 'ip', 'i') rescue
  791.                         Win32API.new(DLL='xinput1_1'  , 'XInputGetState', 'ip', 'i') rescue
  792.                         Win32API.new(DLL='xinput9_1_0', 'XInputGetState', 'ip', 'i') rescue
  793.                         DLL=nil)
  794.       XInputSetState =  Win32API.new(DLL              , 'XInputSetState', 'ip', 'i') if DLL
  795.       def initialize(id)
  796.         super
  797.         @buffer = "\0"*16
  798.         @state = @buffer.unpack('LSC2s4')
  799.         @vibration_state = Array.new(2) {[0,0,0,0,0,false]}
  800.         for k,v in {
  801.         A        =>[:button,12], B       =>[:button,13], X       =>[:button,14],
  802.         Y        =>[:button,15], LB      =>[:button, 8], RB      =>[:button, 9],
  803.         LT       =>[:trigger,0], RT      =>[:trigger,1], BACK    =>[:button, 5],
  804.         START    =>[:button, 4], LS      =>[:button, 6], RS      =>[:button, 7],
  805.         AxisLX_0 =>[:axis_0, 0], AxisLX_1=>[:axis_1, 0], AxisLY_1=>[:axis_1, 1],
  806.         AxisLY_0 =>[:axis_0, 1], AxisRX_0=>[:axis_0, 2], AxisRX_1=>[:axis_1, 2],
  807.         AxisRY_1 =>[:axis_1, 3], AxisRY_0=>[:axis_0, 3], DPadUp  =>[:button, 0],
  808.         DPadRight=>[:button, 3], DPadDown=>[:button, 1], DPadLeft=>[:button, 2]}
  809.           @map[k.i] = v
  810.         end
  811.         update
  812.       end
  813.       def update
  814.         return unless @enabled and !@unplugged = XInputGetState.call(@id, @buffer) != 0
  815.         @state.replace(@buffer.unpack('LSC2s4'))
  816.         super
  817.         update_vibration if @vibration
  818.       end
  819.       def update_vibration
  820.         vibrate = false
  821.         @vibration_state.each do |v|
  822.           next unless v[5]
  823.           last_v0 = v[0]
  824.           if    v[2]>0; v[0] = (v[0]*(v[2]-=1)+v[1]) / (v[2]+1.0)
  825.           elsif v[3]>0; v[0], v[3] = v[1], v[3]-1
  826.           elsif v[4]>0; v[0] = v[0]*(v[4]-=1) / (v[4]+1.0)
  827.           else          v[0], v[5] = 0, false
  828.           end
  829.           vibrate = true if last_v0 != v[0]
  830.         end
  831.         set_vibration if vibrate
  832.       end
  833.       def vibration=(b) vibrate!(2,0,0,0,0); super end
  834.       def vibrate!(id, speed, fade_in, duration, fade_out)
  835.         case id
  836.         when 0, 1; @vibration_state[id][1,5] = [speed, fade_in, duration, fade_out, true]
  837.         when 2   ; 2.times {|i| vibrate!(i, speed, fade_in, duration, fade_out)}
  838.         end
  839.       end
  840.     private
  841.       def button(i)   @state[1][i] == 1 end
  842.       def axis_raw(i) @state[4+i]       end
  843.       def trig_raw(i) @state[2+i]       end
  844.       def set_vibration
  845.         return unless @enabled and @vibration and !@unplugged
  846.         XInputSetState.call(@id, [@vibration_state[0][0]*0xFFFF,
  847.                                   @vibration_state[1][0]*0xFFFF].pack('S2'))
  848.       end
  849.     end
  850.    
  851.   end
  852.  
  853.   class Keyboard < Device
  854.     ::Keyboard = self
  855.     GetKeyboardState    = Win32API.new('user32'  , 'GetKeyboardState'   , 'p'       , 'i')
  856.     getKeyNameText      = Win32API.new('user32'  , 'GetKeyNameTextW'    , 'ipi'     , 'i')
  857.     mapVirtualKey       = Win32API.new('user32'  , 'MapVirtualKey'      , 'ii'      , 'i')
  858.     SendInput           = Win32API.new('user32'  , 'SendInput'          , 'ipi'     , 'i')
  859.     ToUnicode           = Win32API.new('user32'  , 'ToUnicode'          , 'iippii'  , 'i')
  860.     WideCharToMultiByte = Win32API.new('kernel32', 'WideCharToMultiByte', 'iipipipp', 'i')
  861.  
  862.     Keys = Array.new(256) {|i| Keyboard_Key.new(i)}
  863.     None, MouseL, MouseR, Cancel, MouseM, MouseX1, MouseX2, n, Back, Tab,
  864.     LineFeed, n, Clear, Enter, n, n, Shift, Control, Alt, Pause, CapsLock,
  865.     KanaMode, n, JunjaMode, FinalMode, KanjiMode, n, Escape, IMEConvert,
  866.     IMENonConvert, IMEAccept, IMEModeChange, Space, PageUp, PageDown, End, Home,
  867.     Left, Up, Right, Down, Select, Print, Execute, PrintScreen, Insert, Delete,
  868.     Help, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, n, n, n, n, n, n, n, A, B, C,
  869.     D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, LWin,
  870.     RWin, Apps, n, Sleep, NumPad0, NumPad1, NumPad2, NumPad3, NumPad4, NumPad5,
  871.     NumPad6, NumPad7, NumPad8, NumPad9, Multiply, Add, Separator, Subtract,
  872.     Decimal, Divide, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13,
  873.     F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, n, n, n, n, n, n, n,
  874.     n, NumLock, Scroll, n, n, n, n, n, n, n, n, n, n, n, n, n, n, LShift,
  875.     RShift, LControl, RControl, LAlt, RAlt, BrowserBack, BrowserForward,
  876.     BrowserRefresh, BrowserStop, BrowserSearch, BrowserFavorites, BrowserHome,
  877.     VolumeMute, VolumeDown, VolumeUp, MediaNextTrack, MediaPreviousTrack,
  878.     MediaStop, MediaPlayPause, LaunchMail, SelectMedia, LaunchApplication1,
  879.     LaunchApplication2, n, n, OemSemicolon, OemPlus, OemComma, OemMinus,
  880.     OemPeriod, OemQuestion, OemTilde, n, n, n, n, n, n, n, n, n, n, n, n, n, n,
  881.     n, n, n, n, n, n, n, n, n, n, n, n, OemOpenBrackets, OemPipe,
  882.     OemCloseBrackets, OemQuotes, Oem8, n, n, OemBackslash, n, n, ProcessKey,
  883.     n, Packet, n, n, n, n, n, n, n, n, n, n, n, n, n, n, Attn, Crsel, Exsel,
  884.     EraseEof, Play, Zoom, NoName, Pa1, OemClear, Unknown = *Keys
  885.     constants.each {|s| k = const_get(s);  k.s = s.to_s if k.is_a?(Key)}
  886.    
  887.     SCAN_CODE = Array.new(256) {|i| mapVirtualKey.call(i, 0)}
  888.     (BrowserBack..LaunchApplication2).each {|k| SCAN_CODE[k.i] = 0}
  889.     for k,code in  {Pause  =>0x0045, PageUp     =>0x0149, PageDown=>0x0151,
  890.     End   =>0x014F, Home   =>0x0147, Left       =>0x014B, Up      =>0x0148,
  891.     Right =>0x014D, Down   =>0x0150, PrintScreen=>0x0137, Insert  =>0x0152,
  892.     Delete=>0x0153, LWin   =>0x015B, RWin       =>0x015C, Apps    =>0x015D,
  893.     Divide=>0x0135, NumLock=>0x0145, RControl   =>0x011D, RAlt    =>0x0138}
  894.       SCAN_CODE[k.i] = code
  895.     end
  896.    
  897.     KEYS_NAME = Array.new(256) do |i|
  898.       if getKeyNameText.call(SCAN_CODE[i]<<16, utf16="\0"*256, 256) > 0
  899.         WideCharToMultiByte.call(65001, 0, utf16, -1, utf8="\0"*256, 256, 0, 0)
  900.         utf8.delete("\0")
  901.       else Keys[i].to_s
  902.       end
  903.     end
  904.    
  905.     TEXT_KEYS = [Space.i] + (D0.i..D9.i).to_a + (A.i..Z.i).to_a +
  906.                 (NumPad0.i..Divide.i).to_a + (146..150).to_a +
  907.                 (OemSemicolon.i..OemTilde.i).to_a + (OemOpenBrackets.i..245).to_a
  908.    
  909.     TEXT_ENTRY_KEYS = TEXT_KEYS + [Back.i,Left.i,Up.i,Right.i,Down.i,Delete.i]
  910.    
  911.     DEAD_KEYS = {
  912.         '`' => {'a'=>'à', 'e'=>'è', 'i'=>'ì', 'o'=>'ò', 'u'=>'ù',
  913.       ' '=>'`', 'A'=>'À', 'E'=>'È', 'I'=>'Ì', 'O'=>'Ò', 'U'=>'Ù'},
  914.      
  915.         '´' => {'a'=>'á', 'e'=>'é', 'i'=>'í', 'o'=>'ó', 'u'=>'ú', 'y'=>'ý',
  916.       ' '=>'´', 'A'=>'Á', 'E'=>'É', 'I'=>'Í', 'O'=>'Ó', 'U'=>'Ú', 'Y'=>'Ý'},
  917.      
  918.         '^' => {'a'=>'â', 'e'=>'ê', 'i'=>'î', 'o'=>'ô', 'u'=>'û',
  919.       ' '=>'^', 'A'=>'Â', 'E'=>'Ê', 'I'=>'Î', 'O'=>'Ô', 'U'=>'Û'},
  920.      
  921.         '¨' => {'a'=>'ä', 'e'=>'ë', 'i'=>'ï', 'o'=>'ö', 'u'=>'ü', 'y'=>'ÿ',
  922.       ' '=>'¨', 'A'=>'Ä', 'E'=>'Ë', 'I'=>'Ï', 'O'=>'Ö', 'U'=>'Ü', 'y'=>'Ÿ'},
  923.      
  924.         '~' => {'a'=>'ã', 'o'=>'õ', 'n'=>'ñ',
  925.       ' '=>'~', 'A'=>'Ã', 'O'=>'Õ', 'N'=>'Ñ'},
  926.     }
  927.    
  928.     def initialize()         super(256); @buffer = "\0"*256                        end
  929.     def get_push(i)          @enabled and @buffer.getbyte(i)[7] == 1               end
  930.     def get_toggle(i)        @enabled and @buffer.getbyte(i)[0] == 1               end
  931.     def get_key_name(i)      i.between?(0, 255) ? KEYS_NAME[i].dup : ''            end
  932.     def key_name(k)          get_key_name(k2i(k))                                  end
  933.     def push!(*a)            set_state(a, true)                                    end
  934.     def release!(*a)         set_state(a, false)                                   end
  935.     def toggle!(*a)          set_state(a, true); set_state(a, false)               end
  936.     def text_entry()         start_text_entry unless @text_entry; @text_entry.dup  end
  937.     def start_text_entry()   (@text_entry = ''; setup(@keys)) unless @text_entry   end
  938.     def stop_text_entry()    (@text_entry = nil; setup(@user_keys)) if @text_entry end
  939.     def swap_mouse_button(b) MouseL.i, MouseR.i = b ? 2 : 1, b ? 1 : 2             end
  940.     def setup(*a)
  941.       @count.fill(0)
  942.       @keys = keyarrayize(@text_entry ? [@user_keys=a, TEXT_ENTRY_KEYS] : a)
  943.     end
  944.     def update
  945.       return unless @enabled
  946.       GetKeyboardState.call(@buffer)
  947.       super
  948.       update_text_entry if @text_entry
  949.     end
  950.     def update_text_entry
  951.       @text_entry = ''
  952.       for i in TEXT_KEYS
  953.         next if !get_repeat(i) or ToUnicode.call(i, 0, @buffer, utf16="\0"*16, 8, 0)==0
  954.         j = ToUnicode.call(i, 0, @buffer, utf16, 8, 0)
  955.         WideCharToMultiByte.call(65001, 0, utf16, 1, utf8="\0"*4, 4, 0, 0)
  956.         utf8.delete!("\0")
  957.         if @dead_key
  958.           a = DEAD_KEYS[@dead_key]
  959.           @text_entry, @dead_key = (a && a[utf8]) || (@dead_key + utf8)
  960.         else j == -1 ? @dead_key=utf8 : @text_entry=utf8
  961.         end
  962.         return
  963.       end
  964.     end
  965.   private
  966.     def set_state(keys, state)
  967.       keys, inputs = keyarrayize(keys), ''
  968.       keys.each {|i| inputs << [1,i,0,state ? 0 : 2,0,0].pack('LSSLLLx8')}
  969.       SendInput.call(keys.size, inputs, 28)
  970.     end
  971.    
  972.     singleton_attach_methods(@o = new)
  973.     Keys.each {|k| k.o = @o}
  974.     def self.o() @o end
  975.   end
  976.  
  977.   class Mouse < Device
  978.     ::Mouse = self
  979.     ClipCursor      = Win32API.new('user32', 'ClipCursor'     , 'p'      , 'i')
  980.     createCursor    = Win32API.new('user32', 'CreateCursor'   , 'iiiiipp', 'i')
  981.     findWindow      = Win32API.new('user32', 'FindWindow'     , 'pp'     , 'i')
  982.     GetClientRect   = Win32API.new('user32', 'GetClientRect'  , 'ip'     , 'i')
  983.     GetCursorPos    = Win32API.new('user32', 'GetCursorPos'   , 'p'      , 'i')
  984.     GetWindowRect   = Win32API.new('user32', 'GetWindowRect'  , 'ip'     , 'i')
  985.     MapWindowPoints = Win32API.new('user32', 'MapWindowPoints', 'iipi'   , 'i')
  986.     PeekMessage     = Win32API.new('user32', 'PeekMessage'    , 'piiii'  , 'i')
  987.     SetClassLong    = Win32API.new('user32', 'SetClassLong'   , 'iii'    , 'i')
  988.     SetCursorPos    = Win32API.new('user32', 'SetCursorPos'   , 'ii'     , 'i')
  989.    
  990.     Keys = Array.new(7) {|i| Mouse_Key.new(i)}
  991.     Left, Middle, Right, X1, X2, WheelUp, WheelDown = *Keys
  992.     constants.each {|s| k = const_get(s);  k.s = s.to_s if k.is_a?(Key)}
  993.    
  994.     HWND = findWindow.call('RGSS Player', 0)
  995.     BlankCursor = createCursor.call(0, 0, 0, 1, 1, "\xFF", "\x00")
  996.     Cache = (defined? RPG::Cache) ? RPG::Cache : ::Cache
  997.    
  998.     alias click_max   ntrigger_max
  999.     alias click_max=  ntrigger_max=
  1000.     alias click_time  ntrigger_time
  1001.     alias click_time= ntrigger_time=
  1002.     attr_accessor :drag_enabled, :drag_auto_clear, :drag_start_size
  1003.     attr_reader   :cursor, :drag
  1004.     def initialize
  1005.       super(7)
  1006.       @map = @count.map{[]}
  1007.       for k,v in {Left    => [:button, Keyboard::MouseL],
  1008.                   Middle  => [:button, Keyboard::MouseM],
  1009.                   Right   => [:button, Keyboard::MouseR],
  1010.                   X1      => [:button, Keyboard::MouseX1],
  1011.                   X2      => [:button, Keyboard::MouseX2],
  1012.                   WheelUp => [:wheel, 1], WheelDown => [:wheel, -1]}
  1013.         @map[k.i] = v
  1014.       end
  1015.       @enabled, @ntrigger_max, @buffer, @keys = false, 3, "\0"*28, (0...7).to_a
  1016.       @drag_enabled, @drag_auto_clear, @drag_start_size = false, false, 10
  1017.       clip
  1018.       initialize_sprites
  1019.     end
  1020.     def initialize_sprites
  1021.       return if @cursor and !@cursor.disposed?
  1022.       @cursor, @drag = Sprite.new, Sprite.new
  1023.       @cursor.z = @drag.z = 0x7FFFFFFF
  1024.       @cursor.visible, @drag.visible = @enabled, @enabled && @drag_enabled
  1025.       @cursor.bitmap = @default_icon = Bitmap.new(8,8)
  1026.       @cursor.bitmap.fill_rect(0, 0, 3, 7, c=Color.new(0,0,0))
  1027.       @cursor.bitmap.fill_rect(0, 0, 7, 3, c)
  1028.       @cursor.bitmap.fill_rect(5, 5, 3, 3, c)
  1029.       @cursor.bitmap.fill_rect(1, 1, 1, 5, c.set(255,255,255))
  1030.       @cursor.bitmap.fill_rect(1, 1, 5, 1, c)
  1031.       @cursor.bitmap.fill_rect(6, 6, 1, 1, c)
  1032.       @drag.bitmap = Bitmap.new(1,1)
  1033.       @drag.bitmap.set_pixel(0, 0, c.set(0,0,255,128))
  1034.       drag_clear
  1035.     end
  1036.     def enabled=(enabled)
  1037.       initialize_sprites
  1038.       drag_clear unless @enabled = enabled
  1039.       SetClassLong.call(HWND, -12, @enabled ? BlankCursor : 0)
  1040.       @cursor.visible, @drag.visible = @enabled, @enabled && @drag_enabled
  1041.     end
  1042.     def drag_enabled=(drag_enabled)
  1043.       initialize_sprites
  1044.       drag_clear unless @drag_enabled = drag_enabled
  1045.       @drag.visible = @enabled && @drag_enabled
  1046.     end
  1047.     def update
  1048.       return unless @enabled
  1049.       super
  1050.       initialize_sprites
  1051.       update_cursor
  1052.       update_drag
  1053.       update_clip
  1054.       update_wheel
  1055.     end
  1056.     def update_cursor
  1057.       GetCursorPos.call(@buffer)
  1058.       MapWindowPoints.call(0, HWND, @buffer, 1)
  1059.       @cursor.update
  1060.       @cursor.x, @cursor.y = *@buffer.unpack('ll')
  1061.     end
  1062.     def update_drag
  1063.       return unless @drag_enabled
  1064.       @drag.update
  1065.       if Left.trigger?
  1066.         drag_clear
  1067.         @drag_start_point = [@cursor.x, @cursor.y]
  1068.       elsif @drag_start_point and Left.press?
  1069.         x, y = *@drag_start_point
  1070.         w, h = @cursor.x-x, @cursor.y-y
  1071.         if w == 0 then w = 1 elsif w < 0 then x -= w *= -1 end
  1072.         if h == 0 then h = 1 elsif h < 0 then y -= h *= -1 end
  1073.         if dragging? or w > @drag_start_size or h > @drag_start_size
  1074.           @drag.x, @drag.y, @drag.zoom_x, @drag.zoom_y = x, y, w, h
  1075.         end
  1076.       elsif @drag_auto_clear and Left.release?
  1077.         drag_clear
  1078.       end
  1079.     end
  1080.     def update_clip
  1081.       ClipCursor.call(@buffer) if case @clip
  1082.       when String; MapWindowPoints.call(HWND, 0, @buffer.replace(@clip), 2)
  1083.       when      1; GetWindowRect.call(HWND, @buffer)
  1084.       when      2; GetClientRect.call(HWND, @buffer)
  1085.                    MapWindowPoints.call(HWND, 0, @buffer, 2)
  1086.       end
  1087.     end
  1088.     def update_wheel
  1089.       @wheel_state = PeekMessage.call(@buffer,HWND,0x020A,0x020A,0)>0 ?
  1090.                      @buffer.getbyte(11)==0 ? 1 : -1 : 0
  1091.     end
  1092.     def on?(x=nil, y=nil, w=nil, h=nil)
  1093.       if !@enabled; false
  1094.       elsif h; @cursor.x.between?(x, x+w) and @cursor.y.between?(y, y+h)
  1095.       elsif w; Math.hypot(x-@cursor.x, y-@cursor.y) <= w
  1096.       elsif y; @cursor.x == x and @cursor.y == y
  1097.       elsif x; on?(x.x, x.y, x.width, x.height)
  1098.       else     GetClientRect.call(HWND, @buffer); on?(*@buffer.unpack('l4'))
  1099.       end
  1100.     end
  1101.     def drag_on?(x, y=nil, w=nil, h=nil)
  1102.       if !@enabled or !@drag_enabled; false
  1103.       elsif h
  1104.         x < @drag.x+drag_width  and @drag.x < x+w and
  1105.         y < @drag.y+drag_height and @drag.y < y+h
  1106.       elsif w
  1107.         sw, sh = drag_width/2, drag_height/2
  1108.         x, y = (x-@drag.x-sw).abs, (y-@drag.y-sh).abs
  1109.         x<=sw+w and y<=sh+w and (x<=sw or y<=sh or Math.hypot(x-sw,y-sh)<=w)
  1110.       elsif y
  1111.         x.between?(@drag.x, @drag.x+drag_width) and
  1112.         y.between?(@drag.y, @drag.y+drag_height)
  1113.       else drag_on?(x.x, x.y, x.width, x.height)
  1114.       end
  1115.     end
  1116.     def icon(s=nil, ox=0, oy=0) @cursor.bitmap, @cursor.ox, @cursor.oy =
  1117.                                 s ? Cache.picture(s) : @default_icon, ox, oy end
  1118.     def clip(x=0, y=nil, w=0, h=0)
  1119.       ClipCursor.call(0)
  1120.       if x.is_a?(Rect); clip(x.x, x.y, x.width, x.height)
  1121.       else @clip = y ? [x, y, w+x, h+y].pack('l4x12') : x
  1122.       end
  1123.     end
  1124.     def click?(k=Left)  get_ntrigger(1, k2i(k))                           end
  1125.     def dclick?(k=Left) get_ntrigger(2, k2i(k))                           end
  1126.     def tclick?(k=Left) get_ntrigger(3, k2i(k))                           end
  1127.     def swap_button(b)  Keyboard.swap_mouse_button(b)                     end
  1128.     def x()             @cursor.x                                         end
  1129.     def x=(x)           set_pos(x, y)                                     end
  1130.     def y()             @cursor.y                                         end
  1131.     def y=(y)           set_pos(x, y)                                     end
  1132.     def dragging?()     @drag.zoom_x != 0                                 end
  1133.     def drag_x()        @drag.x                                           end
  1134.     def drag_y()        @drag.y                                           end
  1135.     def drag_width()    @drag.zoom_x.to_i                                 end
  1136.     def drag_height()   @drag.zoom_y.to_i                                 end
  1137.     def drag_rect()     Rect.new(drag_x, drag_y, drag_width, drag_height) end
  1138.     def drag_clear
  1139.       @drag_start_point = nil
  1140.       @drag.x = @drag.y = @drag.zoom_x = @drag.zoom_y = 0
  1141.     end
  1142.     def get_push(i)
  1143.       return false unless @enabled
  1144.       j, k = *@map[i]
  1145.       case j
  1146.       when :button; k.push?
  1147.       when :wheel ; k == @wheel_state
  1148.       else          false
  1149.       end
  1150.     end
  1151.     def get_toggle(i)
  1152.       return false unless @enabled
  1153.       j, k = *@map[i]
  1154.       case j
  1155.       when :button; k.toggle?
  1156.       else          false
  1157.       end
  1158.     end
  1159.   private
  1160.     def set_pos(x, y)
  1161.       @cursor.x, @cursor.y = x, y
  1162.       MapWindowPoints.call(HWND, 0, s=[x,y].pack('ll'), 1)
  1163.       SetCursorPos.call(*s.unpack('ll'))
  1164.     end
  1165.    
  1166.     singleton_attach_methods(@o = new)
  1167.     Keys.each {|k| k.o = @o}
  1168.     def self.o() @o end
  1169.   end
  1170.  
  1171.   class Text_Entry_Box < Sprite
  1172.     ::Text_Entry_Box = self
  1173.     SPECIAL_CHARS_CASE = {
  1174.       'à'=>'À', 'è'=>'È', 'ì'=>'Ì', 'ò'=>'Ò', 'ù'=>'Ù',
  1175.       'á'=>'Á', 'é'=>'É', 'í'=>'Í', 'ó'=>'Ó', 'ú'=>'Ú', 'ý'=>'Ý',
  1176.       'â'=>'Â', 'ê'=>'Ê', 'î'=>'Î', 'ô'=>'Ô', 'û'=>'Û',
  1177.       'ä'=>'Ä', 'ë'=>'Ë', 'ï'=>'Ï', 'ö'=>'Ö', 'ü'=>'Ü', 'ÿ'=>'Ÿ',
  1178.       'ã'=>'Ã',                     'õ'=>'Õ',                     'ñ'=>'Ñ',
  1179.     }
  1180.     def self.initialize
  1181.       @@boxes, @@last_icon = [], nil
  1182.       @@icon = [Bitmap.new(9,20), 4, 0] # [bmp, ox, oy]
  1183.       @@icon[0].fill_rect(0,  0, 9,  3, c=Color.new(0,0,0))
  1184.       @@icon[0].fill_rect(0, 17, 9,  3, c)
  1185.       @@icon[0].fill_rect(3,  3, 3, 14, c)
  1186.       @@icon[0].fill_rect(1,  1, 3,  1, c.set(255,255,255))
  1187.       @@icon[0].fill_rect(5,  1, 3,  1, c)
  1188.       @@icon[0].fill_rect(1, 18, 3,  1, c)
  1189.       @@icon[0].fill_rect(5, 18, 3,  1, c)
  1190.       @@icon[0].fill_rect(4,  2, 1, 16, c)
  1191.     end
  1192.     initialize
  1193.     attr_accessor :enabled, :mouse, :focus, :back_color, :select_color,
  1194.                   :text, :allow_c, :select, :case, :size_max, :width_max
  1195.     def initialize(width, height, viewport=nil)
  1196.       super(viewport)
  1197.       @back_color, @select_color = Color.new(0,0,0,0), Color.new(0,0,255,128)
  1198.       @text, @text_width, @allow_c = '', [], ''
  1199.       @enabled = @mouse = @select = true
  1200.       @case = @size_max = @width_max = @pos = @sel = @off = 0
  1201.       @text_chars = [] if RUBY_VERSION == '1.8.1'
  1202.       width = 640 if width > 640 and RUBY_VERSION == '1.9.2'
  1203.       self.bitmap = Bitmap.new(width, height)
  1204.       self.class.initialize if @@icon[0].disposed?
  1205.       @@boxes.delete_if {|s| s.disposed?}
  1206.       @focus = @@boxes.empty?
  1207.       @@boxes << self
  1208.     end
  1209.     def width()  bitmap.width                                      end
  1210.     def height() bitmap.height                                     end
  1211.     def font()   bitmap.font                                       end
  1212.     def font=(f) bitmap.font = f                                   end
  1213.     def hover?() Mouse.on?(x-ox, y-oy, width, height)              end
  1214.     def focus!() @@boxes.each {|s| s.focus = false}; @focus = true end
  1215.     def dispose
  1216.       super
  1217.       @@boxes.delete_if {|s| s.disposed?}
  1218.       Keyboard.stop_text_entry
  1219.       bitmap.dispose
  1220.     end
  1221.     def update
  1222.       super
  1223.       return unless @enabled
  1224.       update_mouse if @mouse
  1225.       return unless @focus
  1226.       if update_text_entry
  1227.         refresh
  1228.       elsif @mouse and (Mouse::WheelDown.press? or Mouse::WheelUp.press?)
  1229.         @off = Mouse::WheelDown.press? ? [@off-16, 0].max :
  1230.                [@off+16, text_width(0, size)+1-width].min
  1231.         draw_text_box
  1232.       elsif Graphics.frame_count % 20 == 0
  1233.         draw_cursor(Graphics.frame_count % 40 == 0)
  1234.       end
  1235.     end
  1236.     def refresh
  1237.       tag = "#{font.name}#{font.size}#{font.bold}#{font.italic}"
  1238.       self.text, @last_font = @text, tag if @last_font != tag
  1239.       min = [text_width(0,@pos)+16-width, text_width(0,size)+1-width].min
  1240.       max = [text_width(0,@pos)-16, 0].max
  1241.       @off = [min, [@off, max].min].max
  1242.       @sel = 0 unless @select
  1243.       draw_text_box
  1244.     end
  1245.   private
  1246.     def update_mouse
  1247.       if hover = hover? and !@@last_icon
  1248.         @@last_icon = [Mouse.cursor.bitmap, Mouse.cursor.ox, Mouse.cursor.oy]
  1249.         Mouse.cursor.bitmap, Mouse.cursor.ox, Mouse.cursor.oy = *@@icon
  1250.       elsif @last_hover != hover and !@last_hover = hover and @@last_icon
  1251.         Mouse.cursor.bitmap, Mouse.cursor.ox, Mouse.cursor.oy = *@@last_icon
  1252.         @@last_icon = nil
  1253.       end
  1254.       if @mouse_select
  1255.         @sel, @mouse_select = @sel+@pos, Mouse::Left.press?
  1256.         @sel -= @pos = get_pos(Mouse.x-x+ox+@off, true)
  1257.       elsif Mouse::Left.trigger? and hover
  1258.         @pos, @sel, @mouse_select = get_pos(Mouse.x-x+ox+@off, true), 0, true
  1259.         Mouse.drag_clear
  1260.         focus!
  1261.       end
  1262.     end
  1263.     def update_text_entry
  1264.       if @mouse_select
  1265.         return false if @last_pos == @pos and @last_sel == @sel
  1266.         @last_pos, @last_sel = @pos, @sel
  1267.       elsif @sel != 0 and (Keyboard::Back.trigger? or Keyboard::Delete.trigger?)
  1268.         @pos -= @sel *= -1 if @sel < 0
  1269.         self[@pos, @sel], @sel = '', 0
  1270.       elsif @pos != 0 and Keyboard::Back.repeat?
  1271.         self[@pos -= 1, 1] = ''
  1272.       elsif @pos != size and Keyboard::Delete.repeat?
  1273.         self[@pos, 1] = ''
  1274.       elsif @pos != 0 and Keyboard::Up.trigger?
  1275.         @sel, @pos = @select && Keyboard::Shift.push? ? @sel+@pos : 0, 0
  1276.       elsif @pos != size and Keyboard::Down.trigger?
  1277.         @sel, @pos = @select && Keyboard::Shift.push? ? @sel+@pos-size : 0, size
  1278.       elsif @pos != 0 and Keyboard::Left.repeat?
  1279.         @pos, @sel = @pos-1, @select && Keyboard::Shift.push? ? @sel+1 : 0
  1280.       elsif @pos != size and Keyboard::Right.repeat?
  1281.         @pos, @sel = @pos+1, @select && Keyboard::Shift.push? ? @sel-1 : 0
  1282.       elsif !Keyboard.text_entry.empty?
  1283.         need_refresh, allowed_chars = false,
  1284.           @case==1 ? downcase(@allow_c) : @case==2 ? upcase(@allow_c) : @allow_c
  1285.         for c in Keyboard.text_entry.split(//)
  1286.           break if @size_max != 0 and @size_max <= size
  1287.           c = @case==1 ? downcase(c) : @case==2 ? upcase(c) : c
  1288.           next unless allowed_chars.empty? or allowed_chars.include?(c)
  1289.           _text, _pos, _sel = @text.dup, @pos, @sel if @width_max != 0
  1290.           @pos -= @sel *= -1 if @sel < 0
  1291.           self[@pos, @sel], @pos, @sel = c, @pos+1, 0
  1292.           if @width_max != 0 and text_width(0, size) > @width_max
  1293.             self.text, @pos, @sel = _text, _pos, _sel
  1294.             break
  1295.           end
  1296.           need_refresh = true
  1297.         end
  1298.         return need_refresh
  1299.       else return false
  1300.       end
  1301.       return true
  1302.     end
  1303.     def draw_text_box
  1304.       bitmap.fill_rect(bitmap.rect, @back_color)
  1305.       draw_selection if @sel != 0
  1306.       draw_text_entry
  1307.       draw_cursor(true)
  1308.     end
  1309.     def draw_selection
  1310.       pos, sel = @sel < 0 ? @pos+@sel : @pos, @sel.abs
  1311.       x, w, h = text_width(0,pos)-@off, text_width(pos,sel), font.size+2
  1312.       bitmap.fill_rect(x, (height-h)/2, w, h, @select_color)
  1313.     end
  1314.     def draw_cursor(blink)
  1315.       color = blink ? font.color : @back_color
  1316.       x, h = text_width(0, @pos)-@off, font.size+2
  1317.       bitmap.fill_rect(x, (height-h)/2, 1, h, color)
  1318.     end
  1319.     def draw_text_entry()
  1320.       bitmap.draw_text(-@off, 0, 0xFFFF, height, @text)
  1321.     end
  1322.     def downcase(str)
  1323.       str = str.downcase
  1324.       SPECIAL_CHARS_CASE.each {|d,u| str.gsub!(u, d)}
  1325.       str
  1326.     end
  1327.     def upcase(str)
  1328.       str = str.upcase
  1329.       SPECIAL_CHARS_CASE.each {|d,u| str.gsub!(d, u)}
  1330.       str
  1331.     end
  1332.     def text_width(i, j)
  1333.       @text_width[i] ||= bitmap.text_size(self[0, i]).width
  1334.       @text_width[i+j] ||= bitmap.text_size(self[0, i+j]).width
  1335.       @text_width[i+j] - @text_width[i]
  1336.     end
  1337.     def get_pos(x, round=false)
  1338.       return 0 if x <= 0
  1339.       return size if x >= text_width(0, size)
  1340.       size.times do |i|
  1341.         if (w = text_width(0,i+1)) > x
  1342.           return i unless round
  1343.           w -= text_width(i,1) / 2
  1344.           return w > x ? i : i+1
  1345.         end
  1346.       end
  1347.     end
  1348.     if RUBY_VERSION == '1.9.2'
  1349.       alias normal_draw_text_entry draw_text_entry
  1350.       def draw_text_entry
  1351.         if text_width(0, size) > 640
  1352.           a, b = get_pos(@off), get_pos(@off+width)
  1353.           b += 1 if b != size and text_width(a, b+1-a) <= 640
  1354.           a += 1 if text_width(a, b-a) > 640
  1355.           x = text_width(0,a)-@off
  1356.           bitmap.draw_text(x, 0, 0xFFFF, height, self[a, b-a])
  1357.         else normal_draw_text_entry
  1358.         end
  1359.       end
  1360.       def [](i, j) @text[i, j] end
  1361.       def []=(i, j, str)
  1362.         @text[i, j] = str
  1363.         @text_width[i, @text_width.size-i] = Array.new(size-i)
  1364.       end
  1365.     public
  1366.       def size()   @text.size  end
  1367.       def text=(str)
  1368.         str = @case==1 ? downcase(str) : @case==2 ? upcase(str) : str
  1369.         @text_width = Array.new(str.size)
  1370.         @text = str
  1371.       end
  1372.     else
  1373.       def [](i, j) @text_chars[i, j].join('') end
  1374.       def []=(i, j, str)
  1375.         @text_chars[i, j] = str.empty? ? nil : str
  1376.         @text_width[i, @text_width.size-i] = Array.new(size-i)
  1377.         @text.replace(@text_chars.join(''))
  1378.       end
  1379.     public
  1380.       def size()   @text_chars.size           end
  1381.       def text=(str)
  1382.         str = @case==1 ? downcase(str) : @case==2 ? upcase(str) : str
  1383.         @text_chars.replace(str.split(//))
  1384.         @text_width = Array.new(@text_chars.size)
  1385.         @text = str
  1386.       end
  1387.     end
  1388.   end
  1389.  
  1390.   def self.[](i) Players[i] end
  1391.   def self.update
  1392.     Keyboard.update
  1393.     Mouse.update
  1394.     Gamepads.each {|g| g.update}
  1395.     Players.each {|p| p.update}
  1396.   end
  1397.   def self.refresh
  1398.     Gamepads.clear
  1399.     x360_pads = XBox360_Gamepad::DLL ? Array.new(4) {|i| XBox360_Gamepad.new(i)} : []
  1400.     x360_pads.sort! {|a,b| (a.unplugged ? 1 : 0) <=> (b.unplugged ? 1 : 0)}
  1401.     devcaps = "\0"*404
  1402.     16.times do |i|
  1403.       Multimedia_Gamepad::JoyGetDevCaps.call(i, devcaps, 404)
  1404.       mid = devcaps.unpack('S')[0]
  1405.       if mid == 1118 and !x360_pads.empty?
  1406.         Gamepads << x360_pads.shift
  1407.       elsif mid != 0
  1408.         Gamepads << Multimedia_Gamepad.new(i)
  1409.       end
  1410.     end
  1411.     Gamepads.sort! {|a,b| (a.unplugged ? 1 : 0) <=> (b.unplugged ? 1 : 0)}
  1412.     Gamepads.each {|g| g.enabled = false}
  1413.     Players.each {|p| p.gamepad_id += 0}
  1414.   end
  1415.  
  1416.   # Le rythme de la fonction repeat? quand on maintient une touche appuyée.
  1417.   # La fonction repeat? est utilisée dans les menus pour bouger le curseur par exemple.
  1418.   f = Graphics.frame_rate
  1419.   REPEAT = [ # (se lit de bas en haut)
  1420.     #[f*4, 1],           # Après 4 secondes retourne toujours true.
  1421.     #[f*2, f*0.05],    # Après 2 secondes retourne true toutes les 0.05 secondes.
  1422.     [f*0.4, f*0.1], # Après 0.4 secondes retourne true toutes les 0.1 secondes.
  1423.     [2, 0],       # ...puis retourne false (à partir de la 2ème frame).
  1424.     [1, 1]      # Retourne true quand on vient d'appuyer (la 1ère frame)...
  1425.   ]
  1426.   PLAYERS_MAX = 1 # Le nombre de joueurs pour les jeux multijoueurs.
  1427.   KEYS_MAX = 30 # Nombre de touches, on peut mettre un très grand nombre si on
  1428.                 # veut mais le limiter au minimum sert à optimiser la mémoire.
  1429.  
  1430.   Gamepads, Players = [], Array.new(PLAYERS_MAX) {|i| Player.new(i)}
  1431.   singleton_attach_methods(Players[0])
  1432.   class Player
  1433.     Keys = Array.new(KEYS_MAX) {|i| Player_Key.new(i)}
  1434.     # Les différentes touches du jeu (id entre 0 et KEYS_MAX-1).
  1435.     DOWN  = Keys[2]
  1436.     LEFT  = Keys[4]
  1437.     RIGHT = Keys[6]
  1438.     UP    = Keys[8]
  1439.     A     = Keys[11]
  1440.     B     = Keys[12]
  1441.     C     = Keys[13]
  1442.     X     = Keys[14]
  1443.     Y     = Keys[15]
  1444.     Z     = Keys[16]
  1445.     L     = Keys[17]
  1446.     R     = Keys[18]
  1447.     SHIFT = Keys[21]
  1448.     CTRL  = Keys[22]
  1449.     ALT   = Keys[23]
  1450.     F5    = Keys[25]
  1451.     F6    = Keys[26]
  1452.     F7    = Keys[27]
  1453.     F8    = Keys[28]
  1454.     F9    = Keys[29]
  1455.    
  1456.     constants.each {|s| Input.const_set(s,k=const_get(s)); k.s = s.to_s if k.is_a?(Key)}
  1457.   end
  1458.  
  1459.   # La config par défaut des touches.
  1460.   # En cas de jeu multijoueur il en faut une différente pour chaque joueur.
  1461.   # Liste des touches du clavier ligne 862.
  1462.   # Liste des touches XBox360 ligne 689, pour manette random ligne 681.
  1463.   # Mais inutile de mettre les deux, par exemple :A et :Button1 sont la même
  1464.   # touche, si moi j'utilise celles d'XBox c'est juste parce que ça me semble
  1465.   # plus logique de régler les touches par rapport à une config connue.
  1466.   # Le mieux étant de faire un menu où le joueur peut configurer lui même tout ça.
  1467.   # Le format est très simple, à gauche les touches virtuelles du jeu, à droite
  1468.   # un tableau des touches correspondantes séparé en deux, 1ère colonne les
  1469.   # touches de la manette, 2ème colonne les touches du clavier.
  1470.   # Pour les jeux multijoueurs la config des manettes se fait pareillement pour
  1471.   # tous, la différenciation des manettes se fait en interne.
  1472.   # Config du joueur 1 :
  1473.   Players[0].setup(
  1474.     :DOWN  => [ [:AxisLY_0, :DPadDown] , [:Down]                 ],
  1475.     :LEFT  => [ [:AxisLX_0, :DPadLeft] , [:Left]                 ],
  1476.     :RIGHT => [ [:AxisLX_1, :DPadRight], [:Right]                ],
  1477.     :UP    => [ [:AxisLY_1, :DPadUp]   , [:Up]                   ],
  1478.     :A     => [ [:X]                   , [:Z, :Shift]            ],
  1479.     :B     => [ [:Y]                   , [:X, :NumPad0, :Escape] ],
  1480.     :C     => [ [:A]                   , [:C, :Enter, :Space]    ],
  1481.     :X     => [ [:B]                   , [:A]                    ],
  1482.     :Y     => [ [:LT]                  , [:S]                    ],
  1483.     :Z     => [ [:RT]                  , [:D]                    ],
  1484.     :L     => [ [:LB]                  , [:Q, :PageUp]           ],
  1485.     :R     => [ [:RB]                  , [:W, :PageDown]         ],
  1486.     :SHIFT => [ []                     , [:Shift]                ],
  1487.     :CTRL  => [ []                     , [:Control]              ],
  1488.     :ALT   => [ []                     , [:Alt]                  ],
  1489.     :F5    => [ []                     , [:F5]                   ],
  1490.     :F6    => [ []                     , [:F6]                   ],
  1491.     :F7    => [ []                     , [:F7]                   ],
  1492.     :F8    => [ []                     , [:F8]                   ],
  1493.     :F9    => [ []                     , [:F9]                   ])
  1494.  
  1495.   refresh
  1496.   update
  1497.   Keyboard.release!(0...256) if Keyboard.push?(*0...256)
  1498. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement